From a8b8038d95ee33834c06fa8fd7470521bb034eac Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Sat, 9 Jul 2016 16:17:45 +0800 Subject: [PATCH 001/688] Ability to override the default warehouse url base Hope this one does override! --- tools/packaging/tropohouse.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/packaging/tropohouse.js b/tools/packaging/tropohouse.js index a30719a232..1e416f9c6b 100644 --- a/tools/packaging/tropohouse.js +++ b/tools/packaging/tropohouse.js @@ -299,6 +299,12 @@ _.extend(exports.Tropohouse.prototype, { // XXX: Error handling. _downloadBuildToTempDir: function (versionInfo, buildRecord) { var url = buildRecord.build.url; + + // Override the download domain name and protocol if METEOR_WAREHOUSE_URLBASE + // provided. + if (process.env.METEOR_WAREHOUSE_URLBASE) { + url = url.replace(/^[a-zA-Z]+:\/\/[^\/]+/, process.env.METEOR_WAREHOUSE_URLBASE); + } // XXX: We use one progress for download & untar; this isn't ideal: // it relies on extractTarGz being fast and not reporting any progress. From 5d4de13cfd0deaddd84da43dd05901e3dc94da7e Mon Sep 17 00:00:00 2001 From: Raghavendra Rachamadugu Date: Mon, 18 Jul 2016 16:20:48 -0700 Subject: [PATCH 002/688] [7397] onLogout should provide connection information Adding an argument to onLogoutCallback. The callback is an object with two properties - userId and connection. I thought of loading up the user and instead have the user property, but felt like this maybe redundant. Logout hooks can always do this if they need. However one advantage of having user instead of userId is it makes it symmetric/consistent with onLogin callback. Let me know if you strongly feel we should have user instead userId.. Also extended an existing test to validate the onLogout callback gets this argument with expected user id --- packages/accounts-base/accounts_server.js | 7 ++++--- packages/accounts-base/accounts_tests.js | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index dbffd61e64..88e785758d 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -176,9 +176,10 @@ Ap._failedLogin = function (connection, attempt) { }); }; -Ap._successfulLogout = function () { +Ap._successfulLogout = function (connection, userId) { + var logoutContext = { userId: userId, connection: connection }; this._onLogoutHook.each(function (callback) { - callback(); + callback(logoutContext); return true; }); }; @@ -537,8 +538,8 @@ Ap._initServerMethods = function () { accounts._setLoginToken(this.userId, this.connection, null); if (token && this.userId) accounts.destroyToken(this.userId, token); + accounts._successfulLogout(this.connection, this.userId); this.setUserId(null); - accounts._successfulLogout(); }; // Delete all the current user's tokens and close all open connections logged diff --git a/packages/accounts-base/accounts_tests.js b/packages/accounts-base/accounts_tests.js index bb8774b7b1..cc56f03a57 100644 --- a/packages/accounts-base/accounts_tests.js +++ b/packages/accounts-base/accounts_tests.js @@ -388,6 +388,9 @@ Tinytest.add( var onLoginStopper = Accounts.onLogin(function(attempt) { test.equal(Meteor.userId(), onLoginExpectedUserId, "onLogin"); }); + var onLogoutStopper = Accounts.onLogout(function(logoutContext) { + test.equal(logoutContext.userId, onLogoutExpectedUserId, "onLogout"); + }); var onLoginFailureStopper = Accounts.onLoginFailure(function(attempt) { test.equal(Meteor.userId(), onLoginFailureExpectedUserId, "onLoginFailure"); }); @@ -408,9 +411,14 @@ Tinytest.add( var onLoginFailureExpectedUserId = userId; test.throws(function() { conn.call('login', { resume: "bogus" }) }, '403'); + // Trigger onLogout callbacks + var onLogoutExpectedUserId = userId; + conn.call('logout'); + conn.disconnect(); validateStopper.stop(); onLoginStopper.stop(); + onLogoutStopper.stop(); onLoginFailureStopper.stop(); } ); From 0e1d3c7f92a36de5887286613aef97b2ce5b8375 Mon Sep 17 00:00:00 2001 From: Raghavendra Rachamadugu Date: Tue, 19 Jul 2016 13:18:23 -0700 Subject: [PATCH 003/688] Add check for connection field in test --- packages/accounts-base/accounts_tests.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/accounts-base/accounts_tests.js b/packages/accounts-base/accounts_tests.js index cc56f03a57..258e0011d4 100644 --- a/packages/accounts-base/accounts_tests.js +++ b/packages/accounts-base/accounts_tests.js @@ -390,6 +390,7 @@ Tinytest.add( }); var onLogoutStopper = Accounts.onLogout(function(logoutContext) { test.equal(logoutContext.userId, onLogoutExpectedUserId, "onLogout"); + test.instanceOf(logoutContext.connection, Object); }); var onLoginFailureStopper = Accounts.onLoginFailure(function(attempt) { test.equal(Meteor.userId(), onLoginFailureExpectedUserId, "onLoginFailure"); From 4a609c278364d165d0babadf591fed146dbf809a Mon Sep 17 00:00:00 2001 From: Raghavendra Rachamadugu Date: Tue, 19 Jul 2016 21:26:50 -0700 Subject: [PATCH 004/688] [7397] Change argument to onLogout callback to be consistent with onLogin argument onLogin argument is an object that has user and connection fields among other fields. So I'm making onLogout also have user and connection fields to make things consistent. Other fields that onLogin callbacks receive include type, allowed, methodName, methodArguments - which are not available or applicable for onLogout. --- packages/accounts-base/accounts_server.js | 4 ++-- packages/accounts-base/accounts_tests.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index 88e785758d..a165ec509b 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -177,9 +177,9 @@ Ap._failedLogin = function (connection, attempt) { }; Ap._successfulLogout = function (connection, userId) { - var logoutContext = { userId: userId, connection: connection }; + const user = userId && this.users.findOne(userId); this._onLogoutHook.each(function (callback) { - callback(logoutContext); + callback({ user, connection }); return true; }); }; diff --git a/packages/accounts-base/accounts_tests.js b/packages/accounts-base/accounts_tests.js index 258e0011d4..5857597221 100644 --- a/packages/accounts-base/accounts_tests.js +++ b/packages/accounts-base/accounts_tests.js @@ -389,7 +389,7 @@ Tinytest.add( test.equal(Meteor.userId(), onLoginExpectedUserId, "onLogin"); }); var onLogoutStopper = Accounts.onLogout(function(logoutContext) { - test.equal(logoutContext.userId, onLogoutExpectedUserId, "onLogout"); + test.equal(logoutContext.user._id, onLogoutExpectedUserId, "onLogout"); test.instanceOf(logoutContext.connection, Object); }); var onLoginFailureStopper = Accounts.onLoginFailure(function(attempt) { From 618d3730ddad5952f86aa8bdfc12ab4a7e0f9665 Mon Sep 17 00:00:00 2001 From: c9s Date: Sat, 23 Jul 2016 22:29:02 +0800 Subject: [PATCH 005/688] Improve the meteor build speed on travis ci run.sh already runs ./meteor --self-test so the install section defined in travis config can be remove. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5ec40272b9..d172d1e022 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ cache: - "dev_bundle" - ".meteor" - ".babel-cache" -install: ./meteor --get-ready script: TEST_PACKAGES_EXCLUDE="less" ./packages/test-in-console/run.sh sudo: false env: From 8169b6fd573722e8b02e30202627ede922e3f037 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 27 Jul 2016 14:09:30 +1000 Subject: [PATCH 006/688] Added a note about replicaSet #7450 --- History.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/History.md b/History.md index 84f0b7520f..13c1d4f198 100644 --- a/History.md +++ b/History.md @@ -29,6 +29,10 @@ 2.6 up. Mongo 2.4 has now reached end-of-life (https://www.mongodb.com/support-policy), and is no longer supported. + If you are setting `MONGO_OPLOG_URL`, especially in production, ensure you are + passing in the `replicaSet` argument (see [#7450] + (https://github.com/meteor/meteor/issues/7450)) + * Custom Mongo options can now be specified using the `Mongo.setConnectionOptions(options)` API. [#7277](https://github.com/meteor/meteor/pull/7277) From 696de365493dd923ff6a9e740241372ca1bdd0b3 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 27 Jul 2016 16:15:51 +1000 Subject: [PATCH 007/688] More subtle logic for deciding when test files should be lazily loaded The logic at the top of this function was basically just for the case of "file is in imports but also a test file". But the logic caught up some other edge cases, such as "file is in node_modules but also a test file". --- tools/isobuild/package-source.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/tools/isobuild/package-source.js b/tools/isobuild/package-source.js index a32f71ded6..39648e1667 100644 --- a/tools/isobuild/package-source.js +++ b/tools/isobuild/package-source.js @@ -1361,21 +1361,16 @@ _.extend(PackageSource.prototype, { _inferFileOptions(relPath, {arch, isApp}) { const fileOptions = {}; - const isAnyTest = global.testCommandMetadata && - (global.testCommandMetadata.isTest || - global.testCommandMetadata.isAppTest); + const isTest = global.testCommandMetadata + && global.testCommandMetadata.isTest; + const isAppTest = global.testCommandMetadata + && global.testCommandMetadata.isAppTest; + const isTestFile = (isTest || isAppTest) && isTestFilePath(relPath); - if (isAnyTest) { - if (isTestFilePath(relPath)) { - // When running tests, test files should not be loaded lazily. - return fileOptions; - } - - // If running in test mode (`meteor test`), all files other than - // test files should be loaded lazily. - if (global.testCommandMetadata.isTest) { - fileOptions.lazy = true; - } + // If running in test mode (`meteor test`), all files other than + // test files should be loaded lazily. + if (isTest && !isTestFile) { + fileOptions.lazy = true; } const dirs = files.pathDirname(relPath).split(files.pathSep); @@ -1392,7 +1387,8 @@ _.extend(PackageSource.prototype, { return fileOptions; } - if (isApp && dir === "imports") { + // Files in `imports/` should be lazily loaded *apart* from tests + if (isApp && dir === "imports" && !isTestFile) { fileOptions.lazy = true; } From c239effdad1d43dfdf922319822d2110998ac911 Mon Sep 17 00:00:00 2001 From: Alon Amster Date: Mon, 23 Nov 2015 23:11:18 +0200 Subject: [PATCH 008/688] Removed the google `profile` scope. The `email` scope is enough for getting the required data, including the user ID. --- packages/google/google_client.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/google/google_client.js b/packages/google/google_client.js index d8a9ea4e9a..b7b673147c 100644 --- a/packages/google/google_client.js +++ b/packages/google/google_client.js @@ -23,9 +23,9 @@ Google.requestCredential = function (options, credentialRequestCompleteCallback) var credentialToken = Random.secret(); - // always need this to get user id from google. - var requiredScope = ['profile']; - var scope = ['email']; + // we need the email scope to get user id from google. + var requiredScope = ['email']; + var scope = []; if (options.requestPermissions) scope = options.requestPermissions; scope = _.union(scope, requiredScope); From ca09e9d19bbf2b741ed11a5a691f539c7ee4d54d Mon Sep 17 00:00:00 2001 From: Alon Amster Date: Wed, 27 Jul 2016 10:53:56 +0300 Subject: [PATCH 009/688] Improve backward compatibility and add note The default value for the `requestPermissions` option is now `profile`, thus preserving the old behavior in case the option was not explicitly set. Added a note in the History.md file regarding this change. --- History.md | 8 ++++++++ packages/google/google_client.js | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 13c1d4f198..12e8096074 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,13 @@ ## v.NEXT +* The `google` package now uses the `email` scope as a mandatory field instead + of the `profile` scope. The `profile` scope is still added by default if the + `requestPermissions` option is not specified to maintain backward + compatibility, but it is now possible to pass an empty array to + `requestPermissions` in order to only request the `email` scope, which + reduces the amount of permissions requested from the user in the Google + popup. [PR #6975](https://github.com/meteor/meteor/pull/6975) + ## v1.4 * Node has been upgraded to 4.4.7. diff --git a/packages/google/google_client.js b/packages/google/google_client.js index b7b673147c..b8af26fee4 100644 --- a/packages/google/google_client.js +++ b/packages/google/google_client.js @@ -25,7 +25,7 @@ Google.requestCredential = function (options, credentialRequestCompleteCallback) // we need the email scope to get user id from google. var requiredScope = ['email']; - var scope = []; + var scope = ['profile']; if (options.requestPermissions) scope = options.requestPermissions; scope = _.union(scope, requiredScope); From 3f1826bf7abb20212c4cefcc1fe483b56ea9eb30 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 21 Jul 2016 16:45:18 -0400 Subject: [PATCH 010/688] Provide bin\7za.exe with Windows dev bundle. --- scripts/generate-dev-bundle.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 704e35c2f5..72d07cd59e 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -35,6 +35,16 @@ cd bin $webclient = New-Object System.Net.WebClient $shell = New-Object -com shell.application +mkdir "$DIR\7z" +cd "$DIR\7z" +$webclient.DownloadFile("http://www.7-zip.org/a/7z1602.msi", "$DIR\7z\7z.msi") +$webclient.DownloadFile("http://www.7-zip.org/a/7z1602-extra.7z", "$DIR\7z\extra.7z") +msiexec /i 7z.msi /quiet /qn /norestart +ping -n 4 127.0.0.1 | out-null +& "C:\Program Files*\7-Zip\7z.exe" x extra.7z +mv 7za.exe "$DIR\bin\7z.exe" +cd "$DIR\bin" + # download node # same node on 32bit vs 64bit? $node_link = "http://nodejs.org/dist/v${NODE_VERSION}/win-x86/node.exe" @@ -63,6 +73,7 @@ foreach($item in $zip.items()) { } rm -Recurse -Force $npm_zip +rm -Recurse -Force "$DIR\7z" # add bin to the front of the path so we can use our own node for building $env:PATH = "${DIR}\bin;${env:PATH}" From 18d70ee780f2a3d002924f94f1b1a60691c9c10d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 22 Jul 2016 14:11:48 -0400 Subject: [PATCH 011/688] Bump $BUNDLE_VERSION to 4.2.0 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index 0ab07e0073..a46bca511c 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.1.4 +BUNDLE_VERSION=4.2.0 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From ed624147d7da62ea9384e53d221010acca62bbf9 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 21 Jul 2016 21:27:09 -0400 Subject: [PATCH 012/688] Use native tar or 7z.exe for extracting tar.gz files when possible. --- tools/fs/files.js | 123 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 21 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index d2bbfd49d2..92bd21ef42 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -12,6 +12,7 @@ var util = require('util'); var _ = require('underscore'); var Fiber = require('fibers'); var crypto = require('crypto'); +var spawn = require("child_process").spawn; var rimraf = require('rimraf'); var sourcemap = require('source-map'); @@ -695,33 +696,26 @@ files.extractTarGz = function (buffer, destPath, options) { var tempDir = files.pathJoin(parentDir, '.tmp' + utils.randomToken()); files.mkdir_p(tempDir); - var tar = require("tar"); - var zlib = require("zlib"); + const startTime = +new Date; + let promise = tryExtractWithNativeTar(buffer, tempDir); - new Promise(function (resolve, reject) { - var gunzip = zlib.createGunzip().on('error', reject); + if (process.platform === "win32") { + promise = promise.catch( + error => tryExtractWithNative7z(buffer, tempDir) + ); + } - var extractor = new tar.Extract({ - path: files.convertToOSPath(tempDir) - }).on('entry', function (e) { - if (process.platform === "win32" || options.forceConvert) { - // On Windows, try to convert old packages that have colons in paths - // by blindly replacing all of the paths. Otherwise, we can't even - // extract the tarball - e.path = colonConverter.convert(e.path); - } - }).on('error', reject) - .on('end', resolve); + promise = promise.catch( + error => tryExtractWithNpmTar(buffer, tempDir) + ); - // write the buffer to the (gunzip|untar) pipeline; these calls - // cause the tar to be extracted to disk. - gunzip.pipe(extractor); - gunzip.write(buffer); - gunzip.end(); - }).await(); + promise.await(); + + console.log("finished extracting in", new Date - startTime, "ms"); // succeed! var topLevelOfArchive = files.readdir(tempDir); + console.log(topLevelOfArchive); if (topLevelOfArchive.length !== 1) { throw new Error( "Extracted archive '" + tempDir + "' should only contain one entry"); @@ -733,6 +727,93 @@ files.extractTarGz = function (buffer, destPath, options) { files.rmdir(tempDir); }; +function tryExtractWithNativeTar(buffer, tempDir) { + const tarProc = spawn("tar", ["xzf", "-"], { + cwd: tempDir, + stdio: "pipe" + }); + + tarProc.stdin.write(buffer); + tarProc.stdin.end(); + + return new Promise((resolve, reject) => { + tarProc.on("error", reject); + tarProc.on("exit", resolve); + }); +} + +function tryExtractWithNative7z(buffer, tempDir) { + const exeOSPath = files.convertToOSPath( + files.pathJoin(files.getCurrentNodeBinDir(), "7z.exe")); + const tarGzBasename = "out.tar.gz"; + const tarGzOSPath = files.convertToOSPath( + files.pathJoin(tempDir, tarGzBasename)); + + files.writeFile(tarGzOSPath, buffer); + + const proc1 = spawn(exeOSPath, ["x", tarGzBasename], { + cwd: tempDir, + stdio: "inherit" // TODO Hide this later. + }); + + return new Promise((resolve, reject) => { + proc1.on("error", reject); + proc1.on("exit", resolve); + }).then(code => { + assert.strictEqual(code, 0); + + let tarBasename; + const foundTar = files.readdir(tempDir).some(file => { + if (file !== tarGzBasename) { + tarBasename = file; + return true; + } + }); + + assert.ok(foundTar, "failed to find .tar file"); + + const proc2 = spawn(exeOSPath, ["x", tarBasename], { + cwd: tempDir, + stdio: "inherit" // TODO Hide this later. + }); + + function cleanUp() { + files.unlink(files.pathJoin(tempDir, tarGzBasename)); + files.unlink(files.pathJoin(tempDir, tarBasename)); + } + + return new Promise((resolve, reject) => { + proc2.on("error", reject); + proc2.on("exit", resolve); + }).then(code => { + cleanUp(); + return code; + }, error => { + cleanUp(); + throw error; + }); + }); +} + +function tryExtractWithNpmTar(buffer, tempDir) { + var tar = require("tar"); + var zlib = require("zlib"); + + return new Promise((resolve, reject) => { + var gunzip = zlib.createGunzip().on('error', reject); + var extractor = new tar.Extract({ + path: files.convertToOSPath(tempDir) + }).on('error', reject) + .on('end', resolve); + + // write the buffer to the (gunzip|untar) pipeline; these calls + // cause the tar to be extracted to disk. + gunzip.pipe(extractor); + gunzip.write(buffer); + gunzip.end(); + }); +} + // Tar-gzips a directory, returning a stream that can then be piped as // needed. The tar archive will contain a top-level directory named // after dirPath. From 136c2f86960b32f67328ba58f1cab61baeb4ef16 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 22 Jul 2016 11:56:25 -0400 Subject: [PATCH 013/688] Don't let previous extraction attempts interfere with later ones. --- tools/fs/files.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/fs/files.js b/tools/fs/files.js index 92bd21ef42..932c0da78b 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -727,7 +727,15 @@ files.extractTarGz = function (buffer, destPath, options) { files.rmdir(tempDir); }; +function ensureDirectoryEmpty(dir) { + files.readdir(dir).forEach(file => { + files.rm_recursive(files.pathJoin(dir, file)); + }); +} + function tryExtractWithNativeTar(buffer, tempDir) { + ensureDirectoryEmpty(tempDir); + const tarProc = spawn("tar", ["xzf", "-"], { cwd: tempDir, stdio: "pipe" @@ -743,6 +751,8 @@ function tryExtractWithNativeTar(buffer, tempDir) { } function tryExtractWithNative7z(buffer, tempDir) { + ensureDirectoryEmpty(tempDir); + const exeOSPath = files.convertToOSPath( files.pathJoin(files.getCurrentNodeBinDir(), "7z.exe")); const tarGzBasename = "out.tar.gz"; @@ -796,6 +806,8 @@ function tryExtractWithNative7z(buffer, tempDir) { } function tryExtractWithNpmTar(buffer, tempDir) { + ensureDirectoryEmpty(tempDir); + var tar = require("tar"); var zlib = require("zlib"); From 4fa4bd73510f703bf65ac24d01a44ceb9ae9d587 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 22 Jul 2016 13:25:38 -0400 Subject: [PATCH 014/688] Fix .tar.gz extraction bugs on Windows. --- tools/fs/files.js | 60 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index 932c0da78b..2e4198adc4 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -714,8 +714,11 @@ files.extractTarGz = function (buffer, destPath, options) { console.log("finished extracting in", new Date - startTime, "ms"); // succeed! - var topLevelOfArchive = files.readdir(tempDir); - console.log(topLevelOfArchive); + var topLevelOfArchive = files.readdir(tempDir) + // On Windows, the 7z.exe tool sometimes creates an auxiliary + // PaxHeader directory. + .filter(file => ! file.startsWith("PaxHeader")); + if (topLevelOfArchive.length !== 1) { throw new Error( "Extracted archive '" + tempDir + "' should only contain one entry"); @@ -724,7 +727,7 @@ files.extractTarGz = function (buffer, destPath, options) { var extractDir = files.pathJoin(tempDir, topLevelOfArchive[0]); makeTreeReadOnly(extractDir); files.rename(extractDir, destPath); - files.rmdir(tempDir); + files.rm_recursive(tempDir); }; function ensureDirectoryEmpty(dir) { @@ -736,17 +739,17 @@ function ensureDirectoryEmpty(dir) { function tryExtractWithNativeTar(buffer, tempDir) { ensureDirectoryEmpty(tempDir); - const tarProc = spawn("tar", ["xzf", "-"], { - cwd: tempDir, - stdio: "pipe" - }); - - tarProc.stdin.write(buffer); - tarProc.stdin.end(); - return new Promise((resolve, reject) => { + const tarProc = spawn("tar", ["xzf", "-"], { + cwd: files.convertToOSPath(tempDir), + stdio: "pipe" + }); + tarProc.on("error", reject); tarProc.on("exit", resolve); + + tarProc.stdin.write(buffer); + tarProc.stdin.end(); }); } @@ -756,19 +759,21 @@ function tryExtractWithNative7z(buffer, tempDir) { const exeOSPath = files.convertToOSPath( files.pathJoin(files.getCurrentNodeBinDir(), "7z.exe")); const tarGzBasename = "out.tar.gz"; - const tarGzOSPath = files.convertToOSPath( - files.pathJoin(tempDir, tarGzBasename)); + const Console = require("../console/console.js").Console; + const spawnOptions = { + cwd: files.convertToOSPath(tempDir), + stdio: Console.verbose ? "inherit" : "pipe", + }; - files.writeFile(tarGzOSPath, buffer); - - const proc1 = spawn(exeOSPath, ["x", tarGzBasename], { - cwd: tempDir, - stdio: "inherit" // TODO Hide this later. - }); + files.writeFile(files.pathJoin(tempDir, tarGzBasename), buffer); return new Promise((resolve, reject) => { - proc1.on("error", reject); - proc1.on("exit", resolve); + spawn(exeOSPath, [ + "x", "-y", tarGzBasename + ], spawnOptions) + .on("error", reject) + .on("exit", resolve); + }).then(code => { assert.strictEqual(code, 0); @@ -782,19 +787,18 @@ function tryExtractWithNative7z(buffer, tempDir) { assert.ok(foundTar, "failed to find .tar file"); - const proc2 = spawn(exeOSPath, ["x", tarBasename], { - cwd: tempDir, - stdio: "inherit" // TODO Hide this later. - }); - function cleanUp() { files.unlink(files.pathJoin(tempDir, tarGzBasename)); files.unlink(files.pathJoin(tempDir, tarBasename)); } return new Promise((resolve, reject) => { - proc2.on("error", reject); - proc2.on("exit", resolve); + spawn(exeOSPath, [ + "x", "-y", tarBasename + ], spawnOptions) + .on("error", reject) + .on("exit", resolve); + }).then(code => { cleanUp(); return code; From 2f40d3bfbb63763266186ff3e9f9f055c5c166ed Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 22 Jul 2016 14:02:02 -0400 Subject: [PATCH 015/688] Refactor verbosity logic for .tar.gz extraction. --- tools/fs/files.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index 2e4198adc4..1e52b55dfd 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -696,23 +696,25 @@ files.extractTarGz = function (buffer, destPath, options) { var tempDir = files.pathJoin(parentDir, '.tmp' + utils.randomToken()); files.mkdir_p(tempDir); + if (! _.has(options, "verbose")) { + options.verbose = require("../console/console.js").Console.verbose; + } + const startTime = +new Date; - let promise = tryExtractWithNativeTar(buffer, tempDir); + let promise = tryExtractWithNativeTar(buffer, tempDir, options); if (process.platform === "win32") { promise = promise.catch( - error => tryExtractWithNative7z(buffer, tempDir) + error => tryExtractWithNative7z(buffer, tempDir, options) ); } promise = promise.catch( - error => tryExtractWithNpmTar(buffer, tempDir) + error => tryExtractWithNpmTar(buffer, tempDir, options) ); promise.await(); - console.log("finished extracting in", new Date - startTime, "ms"); - // succeed! var topLevelOfArchive = files.readdir(tempDir) // On Windows, the 7z.exe tool sometimes creates an auxiliary @@ -728,6 +730,10 @@ files.extractTarGz = function (buffer, destPath, options) { makeTreeReadOnly(extractDir); files.rename(extractDir, destPath); files.rm_recursive(tempDir); + + if (options.verbose) { + console.log("Finished extracting in", new Date - startTime, "ms"); + } }; function ensureDirectoryEmpty(dir) { @@ -736,13 +742,18 @@ function ensureDirectoryEmpty(dir) { }); } -function tryExtractWithNativeTar(buffer, tempDir) { +function tryExtractWithNativeTar(buffer, tempDir, options) { ensureDirectoryEmpty(tempDir); return new Promise((resolve, reject) => { - const tarProc = spawn("tar", ["xzf", "-"], { + const flags = options.verbose ? "-xzvf" : "-xzf"; + const tarProc = spawn("tar", [flags, "-"], { cwd: files.convertToOSPath(tempDir), - stdio: "pipe" + stdio: options.verbose ? [ + "pipe", // Always need to write to tarProc.stdin. + process.stdout, + process.stderr + ] : "pipe", }); tarProc.on("error", reject); @@ -753,16 +764,15 @@ function tryExtractWithNativeTar(buffer, tempDir) { }); } -function tryExtractWithNative7z(buffer, tempDir) { +function tryExtractWithNative7z(buffer, tempDir, options) { ensureDirectoryEmpty(tempDir); const exeOSPath = files.convertToOSPath( files.pathJoin(files.getCurrentNodeBinDir(), "7z.exe")); const tarGzBasename = "out.tar.gz"; - const Console = require("../console/console.js").Console; const spawnOptions = { cwd: files.convertToOSPath(tempDir), - stdio: Console.verbose ? "inherit" : "pipe", + stdio: options.verbose ? "inherit" : "pipe", }; files.writeFile(files.pathJoin(tempDir, tarGzBasename), buffer); @@ -809,7 +819,7 @@ function tryExtractWithNative7z(buffer, tempDir) { }); } -function tryExtractWithNpmTar(buffer, tempDir) { +function tryExtractWithNpmTar(buffer, tempDir, options) { ensureDirectoryEmpty(tempDir); var tar = require("tar"); From 277fa504a77fc0f230d834d73c1b0ead15aba8ea Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 22 Jul 2016 15:28:10 -0400 Subject: [PATCH 016/688] Honor options.forceConvert in tryExtractWithNpmTar. --- tools/fs/files.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/fs/files.js b/tools/fs/files.js index 1e52b55dfd..02f3d9ab15 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -745,6 +745,11 @@ function ensureDirectoryEmpty(dir) { function tryExtractWithNativeTar(buffer, tempDir, options) { ensureDirectoryEmpty(tempDir); + if (options.forceConvert) { + return Promise.reject(new Error( + "Native tar cannot convert colons in package names")); + } + return new Promise((resolve, reject) => { const flags = options.verbose ? "-xzvf" : "-xzf"; const tarProc = spawn("tar", [flags, "-"], { @@ -767,6 +772,11 @@ function tryExtractWithNativeTar(buffer, tempDir, options) { function tryExtractWithNative7z(buffer, tempDir, options) { ensureDirectoryEmpty(tempDir); + if (options.forceConvert) { + return Promise.reject(new Error( + "Native 7z.exe cannot convert colons in package names")); + } + const exeOSPath = files.convertToOSPath( files.pathJoin(files.getCurrentNodeBinDir(), "7z.exe")); const tarGzBasename = "out.tar.gz"; @@ -829,6 +839,13 @@ function tryExtractWithNpmTar(buffer, tempDir, options) { var gunzip = zlib.createGunzip().on('error', reject); var extractor = new tar.Extract({ path: files.convertToOSPath(tempDir) + }).on('entry', function (e) { + if (process.platform === "win32" || options.forceConvert) { + // On Windows, try to convert old packages that have colons in + // paths by blindly replacing all of the paths. Otherwise, we + // can't even extract the tarball + e.path = colonConverter.convert(e.path); + } }).on('error', reject) .on('end', resolve); From 23a3ba0e7201c339b63ee45ec867215403aee9cb Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 28 Jul 2016 14:42:45 -0400 Subject: [PATCH 017/688] Use getUrlWithResuming for publish-for-arch, and log extraction. --- tools/cli/commands-packages.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index 701ebbd4d7..901e3f5c5d 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -603,15 +603,21 @@ main.registerCommand({ // Download the source to the package. var sourceTarball = buildmessage.enterJob("downloading package source", function () { - return httpHelpers.getUrl({ + return httpHelpers.getUrlWithResuming({ url: pkgVersion.source.url, encoding: null }); }); + if (buildmessage.hasMessages()) { + return 1; + } + var sourcePath = files.mkdtemp('package-source'); - // XXX check tarballHash! - files.extractTarGz(sourceTarball, sourcePath); + buildmessage.enterJob("extracting package source", () => { + // XXX check tarballHash! + files.extractTarGz(sourceTarball, sourcePath); + }); // XXX Factor out with packageClient.bundleSource so that we don't // have knowledge of the tarball structure in two places. From 2c67d64585dfe489c62c2be862b81ecb6f1e428a Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 28 Jul 2016 14:43:47 -0400 Subject: [PATCH 018/688] Use getUrlWithResuming in downloadPackagesToWarehouse. --- tools/packaging/warehouse.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/packaging/warehouse.js b/tools/packaging/warehouse.js index e17f33d4d7..b37bda6ee9 100644 --- a/tools/packaging/warehouse.js +++ b/tools/packaging/warehouse.js @@ -394,8 +394,13 @@ _.extend(warehouse, { "/" + version + "/" + name + '-' + version + "-" + platform + ".tar.gz"; - var tarball = httpHelpers.getUrl({url: packageUrl, encoding: null}); + var tarball = httpHelpers.getUrlWithResuming({ + url: packageUrl, + encoding: null + }); + files.extractTarGz(tarball, packageDir); + if (!dontWriteFreshFile) { files.writeFile(warehouse.getPackageFreshFile(name, version), ''); } From 536eecea01bff1a285f0a4569ab95548e4877e9e Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 28 Jul 2016 14:44:46 -0400 Subject: [PATCH 019/688] Log package extraction and loading separately from downloading. https://github.com/meteor/meteor/pull/7457#issuecomment-235881746 Helps with #7283. --- tools/packaging/tropohouse.js | 82 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/tools/packaging/tropohouse.js b/tools/packaging/tropohouse.js index f5739182ec..0607f46c34 100644 --- a/tools/packaging/tropohouse.js +++ b/tools/packaging/tropohouse.js @@ -293,33 +293,6 @@ _.extend(exports.Tropohouse.prototype, { }); }, - // Contacts the package server, downloads and extracts a tarball for a given - // buildRecord into a temporary directory, whose path is returned. - // - // XXX: Error handling. - _downloadBuildToTempDir: function (versionInfo, buildRecord) { - var url = buildRecord.build.url; - - // Override the download domain name and protocol if METEOR_WAREHOUSE_URLBASE - // provided. - if (process.env.METEOR_WAREHOUSE_URLBASE) { - url = url.replace(/^[a-zA-Z]+:\/\/[^\/]+/, process.env.METEOR_WAREHOUSE_URLBASE); - } - - // XXX: We use one progress for download & untar; this isn't ideal: - // it relies on extractTarGz being fast and not reporting any progress. - // Really, we should create two subtasks - // (and, we should stream the download to the tar extractor) - var packageTarball = httpHelpers.getUrlWithResuming({ - url: url, - encoding: null, - progress: buildmessage.getCurrentProgressTracker(), - wait: false - }); - - return exports._extractAndConvert(packageTarball); - }, - // Given a package name and version, returns the architectures for // which we have downloaded this package // @@ -493,36 +466,65 @@ _.extend(exports.Tropohouse.prototype, { // XXX how does concurrency work here? we could just get errors if we // try to rename over the other thing? but that's the same as in // warehouse? - _.each(buildsToDownload, function (build) { - buildmessage.enterJob({ + _.each(buildsToDownload, ({ build: { url }}) => { + const packageTarball = buildmessage.enterJob({ title: "downloading " + packageName + "@" + version + "..." - }, function() { + }, () => { try { - var buildTempDir = self._downloadBuildToTempDir( - { packageName: packageName, version: version }, build); + // Override the download domain name and protocol if METEOR_WAREHOUSE_URLBASE + // provided. + if (process.env.METEOR_WAREHOUSE_URLBASE) { + url = url.replace( + /^[a-zA-Z]+:\/\/[^\/]+/, + process.env.METEOR_WAREHOUSE_URLBASE + ); + } + + return httpHelpers.getUrlWithResuming({ + url: url, + encoding: null, + progress: buildmessage.getCurrentProgressTracker(), + wait: false + }); + } catch (e) { - if (!(e instanceof files.OfflineError)) { + if (! (e instanceof files.OfflineError)) { throw e; } buildmessage.error(e.error.message); } + }); + + if (buildmessage.jobHasMessages()) { + return; + } + + buildmessage.enterJob({ + title: "extracting " + packageName + "@" + version + "..." + }, () => { + const buildTempDir = exports._extractAndConvert(packageTarball); buildInputDirs.push(buildTempDir); buildTempDirs.push(buildTempDir); }); }); + if (buildmessage.jobHasMessages()) { return; } - // We need to turn our builds into a single isopack. - var isopack = new Isopack(); - _.each(buildInputDirs, function (buildTempDir, i) { - isopack._loadUnibuildsFromPath(packageName, buildTempDir, { - firstIsopack: i === 0, + buildmessage.enterJob({ + title: "loading " + packageName + "@" + version + "..." + }, () => { + // We need to turn our builds into a single isopack. + var isopack = new Isopack(); + _.each(buildInputDirs, (buildTempDir, i) => { + isopack._loadUnibuildsFromPath(packageName, buildTempDir, { + firstIsopack: i === 0, + }); }); - }); - self._saveIsopack(isopack, packageName, version); + self._saveIsopack(isopack, packageName, version); + }); // Delete temp directories now (asynchronously). _.each(buildTempDirs, function (buildTempDir) { From 98aaaed084fd87ab8003f0c2839705acdf965789 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 29 Jul 2016 12:23:04 +1000 Subject: [PATCH 020/688] Fix #7491 by wrapping child process in `script` on OSX See https://github.com/meteor/meteor/issues/7491#issuecomment-235887764 NOTE: this issue should be fixed in the next release of node v4 (4.4.8 or 4.5). When we include that in the dev bundle we should revert this change --- tools/cli/main.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/cli/main.js b/tools/cli/main.js index b04ad74fe6..e5ab1f1d06 100644 --- a/tools/cli/main.js +++ b/tools/cli/main.js @@ -493,6 +493,14 @@ var springboard = function (rel, options) { }).await()); } + // On OSX, there is a bug in node 4 when launching out to a node 0.10 process + // This should be fixed in the next release of node (we should then revert + // this change) https://github.com/meteor/meteor/issues/7491 + if (process.platform === 'darwin') { + newArgv.unshift('-q', '/dev/null', executable); + executable = 'script'; + } + // Now exec; we're not coming back. require('kexec')(executable, newArgv); throw Error('exec failed?'); From 7485f021182adb69655bdcfdbf4dddf6f4f5b954 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 29 Jul 2016 12:26:41 +1000 Subject: [PATCH 021/688] Trying 1.4.0.1-rc.2 --- packages/meteor-tool/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index dca5e85d20..5f571e4cad 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.4.0' + version: '1.4.0-1-rc.2' }); Package.includeTool(); diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 56fb5520a2..4476f8bab3 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4-rc.2", + "version": "1.4.0.1-rc.2", "recommended": false, "official": false, "description": "Meteor" From 57dfb0b4e164a0eb70e8f1406c4b352560021ed7 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 29 Jul 2016 13:19:14 +1000 Subject: [PATCH 022/688] Don't try and use wired tiger on 32bit linux For https://github.com/meteor/meteor/issues/7511 --- tools/runners/run-mongo.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/runners/run-mongo.js b/tools/runners/run-mongo.js index d666c17c7a..9f9b692a20 100644 --- a/tools/runners/run-mongo.js +++ b/tools/runners/run-mongo.js @@ -55,8 +55,9 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) { '--replSet', replSetName ]; - // Use mmapv1 on windows, as our binary doesn't support WT - if (process.platform === "win32") { + // Use mmapv1 on 32bit platforms, as our binary doesn't support WT + if (process.platform === "win32" + || (process.platform === "linux" && process.arch === "ia32")) { args.push('--storageEngine', 'mmapv1', '--smallfiles'); } else { // The WT journal seems to be at least 300MB, which is just too much From c47aae693dcf8b9fbd43ce208c9ee4eac182d872 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 29 Jul 2016 13:20:19 +1000 Subject: [PATCH 023/688] Release 1.4.0.1-rc.3 --- packages/meteor-tool/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 5f571e4cad..241dfbffdf 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.4.0-1-rc.2' + version: '1.4.0-1-rc.3' }); Package.includeTool(); diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 4476f8bab3..acf7469cac 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.0.1-rc.2", + "version": "1.4.0.1-rc.3", "recommended": false, "official": false, "description": "Meteor" From 821fa36fcd6ee9365d6da975a0355b3d13d58fcc Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 29 Jul 2016 16:02:45 +1000 Subject: [PATCH 024/688] Update changelog for 1.4.0.1 release --- History.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/History.md b/History.md index 13c1d4f198..9f642f9e67 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,11 @@ ## v.NEXT +## v1.4.0.1 + +* Fix issue with the 1.4 tool springboarding to older releases (see [Issue #7491](https://github.com/meteor/meteor/issues/7491)) + +* Fix issue with running in development on Linux 32bit [Issue #7511](https://github.com/meteor/meteor/issues/7511) + ## v1.4 * Node has been upgraded to 4.4.7. From 67c3664e167e147c7c10042dd3f540653df6da78 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 29 Jul 2016 16:06:55 +1000 Subject: [PATCH 025/688] Preparing 1.4.0.1 release --- packages/meteor-tool/package.js | 2 +- scripts/admin/meteor-release-official.json | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 241dfbffdf..09098a8829 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.4.0-1-rc.3' + version: '1.4.0-1' }); Package.includeTool(); diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index 996cb5ecf3..3940331155 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,7 +1,8 @@ { "track": "METEOR", - "version": "1.4", + "version": "1.4.0.1", "recommended": false, "official": true, - "description": "The Official Meteor Distribution" + "description": "The Official Meteor Distribution", + "patchFrom": ["1.4"] } From 57a28eafff7c173f4889ff1feec5940f36cc12e1 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Sat, 30 Jul 2016 04:43:53 +0800 Subject: [PATCH 026/688] Have `meteor update` explain how to update cordova packages (#7233) --- tools/cli/commands-packages.js | 40 +++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index 901e3f5c5d..d93a4b4aab 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1621,6 +1621,34 @@ main.registerCommand({ upgradePackageNames = options.args; } + const upgradePackagesWithoutCordova = + upgradePackageNames.filter(name => name.split(':')[0] !== 'cordova'); + if (!_.isEqual(upgradePackagesWithoutCordova, upgradePackageNames)) { + // There are some cordova packages in the list to update. + // We should tell users how to update cordova packages. + Console.warn(); + Console.warn("To add/upgrade a Cordova plugin in your Meteor project, run:"); + Console.warn(); + Console.warn( + Console.command("meteor add cordova:PLUGIN-NAME@x.y.z"), + Console.options({ indent: 2 })); + Console.warn(); + Console.warn("The 'PLUGIN-NAME' should be an official plugin name", + "(e.g. cordova-plugin-media) and the 'x.y.z' should be an available version of", + "the plugin. The latest version can be found with the following command:"); + Console.warn(); + Console.warn( + Console.command("meteor npm view PLUGIN-NAME version"), + Console.options({ indent: 2 })); + if (upgradePackagesWithoutCordova.length !== 0) { + Console.warn(); + Console.warn('The non-Cordova packages will now be updated...'); + } + Console.warn(); + // Exclude cordova packages + upgradePackageNames = upgradePackagesWithoutCordova; + } + // Try to resolve constraints, allowing the given packages to be upgraded. projectContext.reset({ upgradePackageNames: upgradePackageNames, @@ -1635,11 +1663,13 @@ main.registerCommand({ // If the user explicitly mentioned some packages to upgrade, they must // actually end up in our solution! - _.each(options.args, function (packageName) { - if (! projectContext.packageMap.getInfo(packageName)) { - buildmessage.error(packageName + ': package is not in the project'); - } - }); + if (options.args.length !== 0) { + _.each(upgradePackageNames, function (packageName) { + if (! projectContext.packageMap.getInfo(packageName)) { + buildmessage.error(packageName + ': package is not in the project'); + } + }); + } if (buildmessage.jobHasMessages()) { return; } From a850b91f2512d70178af6c70f8d29f8818e45774 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Sat, 30 Jul 2016 19:22:51 +0200 Subject: [PATCH 027/688] Update README.md Use the install command shown at https://www.meteor.com/install --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 021c811f0d..f27f3c1ff5 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Next, read the [guide](http://guide.meteor.com) or the reference documentation a Install Meteor: ```bash -curl https://install.meteor.com | /bin/sh +curl https://install.meteor.com/ | sh ``` Create a project: From 7769951ee888f16512c601676de6c682c8a43467 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 1 Aug 2016 17:55:37 +1000 Subject: [PATCH 028/688] Switched to concat-stream for performance --- scripts/dev-bundle-tool-package.js | 2 +- tools/tests/utils-tests.js | 1 + tools/utils/http-helpers.js | 26 ++++++++++++-------------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 0649543971..f85665143a 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -55,7 +55,7 @@ var packageJson = { 'lru-cache': '2.6.4', 'cordova-lib': "6.0.0", longjohn: '0.2.11', - 'stream-buffers': '3.0.0' + 'concat-stream': '1.5.1' } }; diff --git a/tools/tests/utils-tests.js b/tools/tests/utils-tests.js index 3cf172e30e..659763a138 100644 --- a/tools/tests/utils-tests.js +++ b/tools/tests/utils-tests.js @@ -177,6 +177,7 @@ selftest.define("resume downloads", ['net'], function () { ++interruptCount; request.emit('error', 'pretend-http-error'); request.emit('end'); + request.abort(); } }); } diff --git a/tools/utils/http-helpers.js b/tools/utils/http-helpers.js index 017f069e41..59485738bb 100644 --- a/tools/utils/http-helpers.js +++ b/tools/utils/http-helpers.js @@ -14,7 +14,7 @@ var release = require('../packaging/release.js'); var Console = require('../console/console.js').Console; var timeoutScaleFactor = require('./utils.js').timeoutScaleFactor; -import { WritableStreamBuffer } from 'stream-buffers'; +import concatStream from 'concat-stream'; // Helper that tracks bytes written to a writable var WritableWithProgress = function (writable, listener) { @@ -393,8 +393,6 @@ _.extend(exports, { url: urlOrOptions, }; - const outputStream = new WritableStreamBuffer(); - const maxAttempts = _.has(options, "maxAttempts") ? options.maxAttempts : 10; @@ -404,13 +402,13 @@ _.extend(exports, { ? options.retryDelaySecs : 5; const masterProgress = options.progress; + const outputStream = concatStream(); - let lastSize = 0; - function attempt(triesRemaining) { - if (lastSize > 0) { + function attempt(triesRemaining = maxAttempts, startAt = 0) { + if (startAt > 0) { options.headers = { ...options.headers, - Range: `bytes=${outputStream.size()}-` + Range: `bytes=${startAt}-` }; } @@ -428,10 +426,9 @@ _.extend(exports, { })); } catch (e) { - const size = outputStream.size(); - const useTry = size === lastSize; - const change = size - lastSize; - lastSize = outputStream.size(); + const size = _.reduce(outputStream.body, (s, buf) => s + buf.length, 0); + const useTry = size === startAt; + const change = size - startAt; if (!useTry || triesRemaining > 0) { if (useTry) { @@ -442,7 +439,7 @@ _.extend(exports, { return new Promise( resolve => setTimeout(resolve, retryDelaySecs * 1000) - ).then(() => attempt(triesRemaining - (useTry ? 1 : 0))); + ).then(() => attempt(triesRemaining - (useTry ? 1 : 0), size)); } Console.debug(`Request failed ${maxAttempts} times: failing`); @@ -450,13 +447,14 @@ _.extend(exports, { } } - const result = attempt(maxAttempts).await(); + + const result = attempt().await(); const response = result.response if (response.statusCode >= 400 && response.statusCode < 600) { const href = response.request.href; throw Error(`Could not get ${href}; server returned [${response.statusCode}]`); } - return outputStream.getContents(); + return outputStream.getBody(); } }); From 155fa2e2479fda99ab913979a8f6b8e1114568f7 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 1 Aug 2016 18:03:21 +1000 Subject: [PATCH 029/688] dev bundle 4.2.1 --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index a46bca511c..09fda2a280 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.0 +BUNDLE_VERSION=4.2.1 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From bb8e1a3b9f92172b50d4d8169e928d5c8890ee79 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 1 Aug 2016 14:42:22 -0400 Subject: [PATCH 030/688] Implement ConcatStream class instead of using concat-stream npm package. --- scripts/dev-bundle-tool-package.js | 3 +-- tools/utils/http-helpers.js | 31 ++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index f85665143a..fd75a4d7a5 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -54,8 +54,7 @@ var packageJson = { runas: "3.1.1", 'lru-cache': '2.6.4', 'cordova-lib': "6.0.0", - longjohn: '0.2.11', - 'concat-stream': '1.5.1' + longjohn: '0.2.11' } }; diff --git a/tools/utils/http-helpers.js b/tools/utils/http-helpers.js index 59485738bb..673da536b7 100644 --- a/tools/utils/http-helpers.js +++ b/tools/utils/http-helpers.js @@ -14,7 +14,30 @@ var release = require('../packaging/release.js'); var Console = require('../console/console.js').Console; var timeoutScaleFactor = require('./utils.js').timeoutScaleFactor; -import concatStream from 'concat-stream'; +import { Writable } from "stream"; + +class ConcatStream extends Writable { + constructor() { + super(); + this.chunks = []; + this.size = 0; + } + + _write(chunk, encoding, next) { + this.chunks.push(chunk); + this.size += chunk.length; + next(); + } + + getBuffer() { + if (this.chunks.length !== 1) { + this.chunks[0] = Buffer.concat(this.chunks); + this.chunks.length = 1; + } + + return this.chunks[0]; + } +} // Helper that tracks bytes written to a writable var WritableWithProgress = function (writable, listener) { @@ -402,7 +425,7 @@ _.extend(exports, { ? options.retryDelaySecs : 5; const masterProgress = options.progress; - const outputStream = concatStream(); + const outputStream = new ConcatStream(); function attempt(triesRemaining = maxAttempts, startAt = 0) { if (startAt > 0) { @@ -426,7 +449,7 @@ _.extend(exports, { })); } catch (e) { - const size = _.reduce(outputStream.body, (s, buf) => s + buf.length, 0); + const size = outputStream.size; const useTry = size === startAt; const change = size - startAt; @@ -455,6 +478,6 @@ _.extend(exports, { throw Error(`Could not get ${href}; server returned [${response.statusCode}]`); } - return outputStream.getBody(); + return outputStream.getBuffer(); } }); From 3dac486a94275b181c964053e8638fb8d04456b2 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 1 Aug 2016 14:42:45 -0400 Subject: [PATCH 031/688] Bump $BUNDLE_VERSION to 4.2.2 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index 09fda2a280..fb80725cda 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.1 +BUNDLE_VERSION=4.2.2 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From c475ffc1617fc9d8d7f19a988f5bcd057f896152 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 1 Aug 2016 19:01:28 -0400 Subject: [PATCH 032/688] Create .meteor/local directory if necessary for `meteor {node,npm}`. Fixes #7546. --- tools/cli/dev-bundle.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cli/dev-bundle.js b/tools/cli/dev-bundle.js index 9d291f4e80..6e032527fe 100644 --- a/tools/cli/dev-bundle.js +++ b/tools/cli/dev-bundle.js @@ -29,7 +29,11 @@ function getDevBundleDir() { var localDir = path.join(path.dirname(releaseFile), "local"); if (! statOrNull(localDir, "isDirectory")) { - return defaultDevBundlePromise; + try { + fs.mkdirSync(localDir); + } catch (e) { + return defaultDevBundlePromise; + } } var devBundleLink = path.join(localDir, "dev_bundle"); From d411ba66d025e0f3d834379554861d50b22b5fa5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 1 Aug 2016 23:58:20 -0400 Subject: [PATCH 033/688] Use native Node aes-gcm support in oauth-encryption package. --- packages/oauth-encryption/encrypt.js | 41 ++++++++++++++-------------- packages/oauth-encryption/package.js | 9 +++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/oauth-encryption/encrypt.js b/packages/oauth-encryption/encrypt.js index f0bb10fdac..ab1ad42140 100644 --- a/packages/oauth-encryption/encrypt.js +++ b/packages/oauth-encryption/encrypt.js @@ -1,12 +1,6 @@ -var crypto = Npm.require("crypto"); -// XXX We hope to be able to use the `crypto` module exclusively when -// Node supports GCM in version 0.11. -var gcm = NpmModuleNodeAesGcm; - -OAuthEncryption = {}; - +var crypto = require("crypto"); var gcmKey = null; - +var OAuthEncryption = exports.OAuthEncryption = {}; // Node leniently ignores non-base64 characters when parsing a base64 // string, but we want to provide a more informative error message if @@ -67,13 +61,19 @@ OAuthEncryption.seal = function (data, userId) { data: data, userId: userId })); + var iv = crypto.randomBytes(12); - var result = gcm.encrypt(gcmKey, iv, plaintext, new Buffer([]) /* aad */); + var cipher = crypto.createCipheriv("aes-128-gcm", gcmKey, iv); + cipher.setAAD(new Buffer([])); + var chunks = [cipher.update(plaintext)]; + chunks.push(cipher.final()); + var encrypted = Buffer.concat(chunks); + return { iv: iv.toString("base64"), - ciphertext: result.ciphertext.toString("base64"), + ciphertext: encrypted.toString("base64"), algorithm: "aes-128-gcm", - authTag: result.auth_tag.toString("base64") + authTag: cipher.getAuthTag().toString("base64") }; }; @@ -96,23 +96,24 @@ OAuthEncryption.open = function (ciphertext, userId) { throw new Error(); } - var result = gcm.decrypt( + var decipher = crypto.createDecipheriv( + "aes-128-gcm", gcmKey, - new Buffer(ciphertext.iv, "base64"), - new Buffer(ciphertext.ciphertext, "base64"), - new Buffer([]), /* aad */ - new Buffer(ciphertext.authTag, "base64") + new Buffer(ciphertext.iv, "base64") ); - if (! result.auth_ok) { - throw new Error(); - } + decipher.setAAD(new Buffer([])); + decipher.setAuthTag(new Buffer(ciphertext.authTag, "base64")); + var chunks = [decipher.update( + new Buffer(ciphertext.ciphertext, "base64"))]; + chunks.push(decipher.final()); + var plaintext = Buffer.concat(chunks).toString("utf8"); var err; var data; try { - data = EJSON.parse(result.plaintext.toString()); + data = EJSON.parse(plaintext); } catch (e) { err = new Error(); } diff --git a/packages/oauth-encryption/package.js b/packages/oauth-encryption/package.js index 14609f0702..be1817470a 100644 --- a/packages/oauth-encryption/package.js +++ b/packages/oauth-encryption/package.js @@ -1,17 +1,16 @@ Package.describe({ summary: "Encrypt account secrets stored in the database", - version: '1.1.13' + version: '1.2.0' }); Package.onUse(function (api) { - api.use("npm-node-aes-gcm@=0.1.7_4"); - - api.export("OAuthEncryption", ["server"]); api.use([ + "modules", "underscore", "ejson" ]); - api.addFiles("encrypt.js", ["server"]); + api.mainModule("encrypt.js", "server"); + api.export("OAuthEncryption", "server"); }); Package.onTest(function (api) { From accde8048f966fe74737268e7fe17a6df52ed023 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 2 Aug 2016 00:00:44 -0400 Subject: [PATCH 034/688] Remove now-unused npm-node-aes-gcm package. --- packages/non-core/npm-node-aes-gcm/.gitignore | 1 - .../npm-node-aes-gcm/.npm/package/.gitignore | 1 - .../npm-node-aes-gcm/.npm/package/README | 7 ------ .../.npm/package/npm-shrinkwrap.json | 23 ------------------- packages/non-core/npm-node-aes-gcm/.versions | 3 --- packages/non-core/npm-node-aes-gcm/README.md | 3 --- packages/non-core/npm-node-aes-gcm/package.js | 15 ------------ packages/non-core/npm-node-aes-gcm/wrapper.js | 14 ----------- 8 files changed, 67 deletions(-) delete mode 100644 packages/non-core/npm-node-aes-gcm/.gitignore delete mode 100644 packages/non-core/npm-node-aes-gcm/.npm/package/.gitignore delete mode 100644 packages/non-core/npm-node-aes-gcm/.npm/package/README delete mode 100644 packages/non-core/npm-node-aes-gcm/.npm/package/npm-shrinkwrap.json delete mode 100644 packages/non-core/npm-node-aes-gcm/.versions delete mode 100644 packages/non-core/npm-node-aes-gcm/README.md delete mode 100644 packages/non-core/npm-node-aes-gcm/package.js delete mode 100644 packages/non-core/npm-node-aes-gcm/wrapper.js diff --git a/packages/non-core/npm-node-aes-gcm/.gitignore b/packages/non-core/npm-node-aes-gcm/.gitignore deleted file mode 100644 index 677a6fc263..0000000000 --- a/packages/non-core/npm-node-aes-gcm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.build* diff --git a/packages/non-core/npm-node-aes-gcm/.npm/package/.gitignore b/packages/non-core/npm-node-aes-gcm/.npm/package/.gitignore deleted file mode 100644 index 3c3629e647..0000000000 --- a/packages/non-core/npm-node-aes-gcm/.npm/package/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/packages/non-core/npm-node-aes-gcm/.npm/package/README b/packages/non-core/npm-node-aes-gcm/.npm/package/README deleted file mode 100644 index 3d492553a4..0000000000 --- a/packages/non-core/npm-node-aes-gcm/.npm/package/README +++ /dev/null @@ -1,7 +0,0 @@ -This directory and the files immediately inside it are automatically generated -when you change this package's NPM dependencies. Commit the files in this -directory (npm-shrinkwrap.json, .gitignore, and this README) to source control -so that others run the same versions of sub-dependencies. - -You should NOT check in the node_modules directory that Meteor automatically -creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/non-core/npm-node-aes-gcm/.npm/package/npm-shrinkwrap.json b/packages/non-core/npm-node-aes-gcm/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index eb10313104..0000000000 --- a/packages/non-core/npm-node-aes-gcm/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "dependencies": { - "meteor-node-aes-gcm": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/meteor-node-aes-gcm/-/meteor-node-aes-gcm-0.1.7.tgz", - "from": "meteor-node-aes-gcm@0.1.7", - "dependencies": { - "node-aes-gcm": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/node-aes-gcm/-/node-aes-gcm-0.1.7.tgz", - "from": "node-aes-gcm@0.1.7", - "dependencies": { - "nan": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.3.tgz", - "from": "nan@>=2.3.0 <2.4.0" - } - } - } - } - } - } -} diff --git a/packages/non-core/npm-node-aes-gcm/.versions b/packages/non-core/npm-node-aes-gcm/.versions deleted file mode 100644 index 3e3de6dc43..0000000000 --- a/packages/non-core/npm-node-aes-gcm/.versions +++ /dev/null @@ -1,3 +0,0 @@ -meteor@1.1.16 -npm-node-aes-gcm@0.1.5_2 -underscore@1.0.9 diff --git a/packages/non-core/npm-node-aes-gcm/README.md b/packages/non-core/npm-node-aes-gcm/README.md deleted file mode 100644 index 65878320f3..0000000000 --- a/packages/non-core/npm-node-aes-gcm/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Using this package on Windows - -This package uses the [node-aes-gcm](https://github.com/xorbit/node-aes-gcm) NPM module, which requires you to have OpenSSL installed on your system to run. To install OpenSSL on Windows, use one of the binaries on [this page](http://slproweb.com/products/Win32OpenSSL.html). Don't forget to install the Visual Studio 2008 redistributables if you don't have them yet. diff --git a/packages/non-core/npm-node-aes-gcm/package.js b/packages/non-core/npm-node-aes-gcm/package.js deleted file mode 100644 index 20a82e1adc..0000000000 --- a/packages/non-core/npm-node-aes-gcm/package.js +++ /dev/null @@ -1,15 +0,0 @@ -Package.describe({ - summary: "Wrapper around the node-aes-gcm npm package", - version: '0.1.7_4', - documentation: null -}); - -Npm.depends({ - 'meteor-node-aes-gcm': '0.1.7' -}); - -Package.onUse(function (api) { - api.use("modules@0.6.1"); - api.export('NpmModuleNodeAesGcm', 'server'); - api.addFiles('wrapper.js', 'server'); -}); diff --git a/packages/non-core/npm-node-aes-gcm/wrapper.js b/packages/non-core/npm-node-aes-gcm/wrapper.js deleted file mode 100644 index 9e944ded31..0000000000 --- a/packages/non-core/npm-node-aes-gcm/wrapper.js +++ /dev/null @@ -1,14 +0,0 @@ -try { - NpmModuleNodeAesGcm = require('meteor-node-aes-gcm'); -} catch (err) { - if (process.platform === "win32" && - err.message.match(/specified module could not be found/)) { - // the user probably doesn't have OpenSSL installed. - throw new Error( -"Couldn't load the package 'meteor-node-aes-gcm'. This is probably because you " + -"don't have OpenSSL installed. See the README for details and directions: " + -"https://github.com/meteor/meteor/blob/devel/packages/non-core/npm-node-aes-gcm/README.md"); - } else { - throw err; - } -} From d4ab84df65c196a1a074e449c1a53de1f9bd23f5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 2 Aug 2016 10:31:32 -0400 Subject: [PATCH 035/688] Update inaccurate comment about AAD data. https://github.com/meteor/meteor/pull/7548#issuecomment-236916851 --- packages/oauth-encryption/encrypt.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/oauth-encryption/encrypt.js b/packages/oauth-encryption/encrypt.js index ab1ad42140..0c6f895fc1 100644 --- a/packages/oauth-encryption/encrypt.js +++ b/packages/oauth-encryption/encrypt.js @@ -48,9 +48,10 @@ OAuthEncryption.loadKey = function (key) { // credentials such as access tokens from being used by a different // user. // -// We would actually like the user id to be AAD (additional -// authenticated data), but the node crypto API does not currently have -// support for specifying AAD. +// We might someday like the user id to be AAD (additional authenticated +// data), but the Node 0.10.x crypto API did not support specifying AAD, +// and it's not clear that we want to incur the compatibility issues of +// relying on that feature, even though it's now supported by Node 4. // OAuthEncryption.seal = function (data, userId) { if (! gcmKey) { From f834b59b5238da1ec25c1232ba765b39b03bfae0 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 2 Aug 2016 10:34:13 -0400 Subject: [PATCH 036/688] Remove underscore dependency from oauth-encryption. --- packages/oauth-encryption/encrypt.js | 9 +++++++-- packages/oauth-encryption/package.js | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/oauth-encryption/encrypt.js b/packages/oauth-encryption/encrypt.js index 0c6f895fc1..d174c96ba5 100644 --- a/packages/oauth-encryption/encrypt.js +++ b/packages/oauth-encryption/encrypt.js @@ -1,6 +1,11 @@ var crypto = require("crypto"); var gcmKey = null; var OAuthEncryption = exports.OAuthEncryption = {}; +var objToStr = Object.prototype.toString; + +function isString(value) { + return objToStr.call(value) === "[object String]"; +} // Node leniently ignores non-base64 characters when parsing a base64 // string, but we want to provide a more informative error message if @@ -11,7 +16,7 @@ var OAuthEncryption = exports.OAuthEncryption = {}; // Exported for the convenience of tests. // OAuthEncryption._isBase64 = function (str) { - return _.isString(str) && /^[A-Za-z0-9\+\/]*\={0,2}$/.test(str); + return isString(str) && /^[A-Za-z0-9\+\/]*\={0,2}$/.test(str); }; @@ -139,7 +144,7 @@ OAuthEncryption.isSealed = function (maybeCipherText) { OAuthEncryption._isBase64(maybeCipherText.iv) && OAuthEncryption._isBase64(maybeCipherText.ciphertext) && OAuthEncryption._isBase64(maybeCipherText.authTag) && - _.isString(maybeCipherText.algorithm); + isString(maybeCipherText.algorithm); }; diff --git a/packages/oauth-encryption/package.js b/packages/oauth-encryption/package.js index be1817470a..7a86ce918a 100644 --- a/packages/oauth-encryption/package.js +++ b/packages/oauth-encryption/package.js @@ -6,7 +6,6 @@ Package.describe({ Package.onUse(function (api) { api.use([ "modules", - "underscore", "ejson" ]); api.mainModule("encrypt.js", "server"); From b8539357101da597778ddc982b580af951b65938 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 2 Aug 2016 10:37:30 -0400 Subject: [PATCH 037/688] Specify version constraints for modules and ejson in oauth-encryption. --- packages/oauth-encryption/package.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/oauth-encryption/package.js b/packages/oauth-encryption/package.js index 7a86ce918a..6712d1363c 100644 --- a/packages/oauth-encryption/package.js +++ b/packages/oauth-encryption/package.js @@ -4,10 +4,8 @@ Package.describe({ }); Package.onUse(function (api) { - api.use([ - "modules", - "ejson" - ]); + api.use("modules@0.7.5", "server"); + api.use("ejson@1.0.12", "server"); api.mainModule("encrypt.js", "server"); api.export("OAuthEncryption", "server"); }); From b165d3e935e38a60c306d17864141c36bdaa8ad7 Mon Sep 17 00:00:00 2001 From: Guillaume Sabran Date: Tue, 2 Aug 2016 09:32:36 -0700 Subject: [PATCH 038/688] Attach to the Facebook scope the function to get fb data from an access token --- packages/facebook/facebook_server.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/facebook/facebook_server.js b/packages/facebook/facebook_server.js index 36ddb48b03..c52ab64ce9 100644 --- a/packages/facebook/facebook_server.js +++ b/packages/facebook/facebook_server.js @@ -2,12 +2,7 @@ Facebook = {}; var querystring = Npm.require('querystring'); - -OAuth.registerService('facebook', 2, null, function(query) { - - var response = getTokenResponse(query); - var accessToken = response.accessToken; - +Facebook.handleAuthFromAccessToken = function handleAuthFromAccessToken(accessToken, expiresAt) { // include all fields from facebook // http://developers.facebook.com/docs/reference/login/public-profile-and-friend-list/ var whitelisted = ['id', 'email', 'name', 'first_name', @@ -17,10 +12,9 @@ OAuth.registerService('facebook', 2, null, function(query) { var serviceData = { accessToken: accessToken, - expiresAt: (+new Date) + (1000 * response.expiresIn) + expiresAt: expiresAt }; - var fields = _.pick(identity, whitelisted); _.extend(serviceData, fields); @@ -28,6 +22,14 @@ OAuth.registerService('facebook', 2, null, function(query) { serviceData: serviceData, options: {profile: {name: identity.name}} }; +}; + +OAuth.registerService('facebook', 2, null, function(query) { + var response = getTokenResponse(query); + var accessToken = response.accessToken; + var expiresIn = response.expiresIn; + + return Facebook.handleAuthFromAccessToken(accessToken, (+new Date) + (1000 * expiresIn)); }); // checks whether a string parses as JSON From 46b9f128ce113d16e304415600dbbb22b0989c59 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 3 Aug 2016 09:15:35 +1000 Subject: [PATCH 039/688] Added some history messages for merged PRs --- History.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/History.md b/History.md index 283316a19f..a3013e786e 100644 --- a/History.md +++ b/History.md @@ -8,6 +8,12 @@ reduces the amount of permissions requested from the user in the Google popup. [PR #6975](https://github.com/meteor/meteor/pull/6975) +* Added `Facebook.handleAuthFromAccessToken` in the case where you get the FB + accessToken in some out-of-band way. [PR #7550](https://github.com/meteor/meteor/pull/7550) + +* `Accounts.onLogout` gets `{ user, connection }` context in a similar fashion + to `Accounts.onLogin`. [Issue #7397](https://github.com/meteor/meteor/issue/7397) [PR #7433](https://github.com/meteor/meteor/pull/7433) + ## v1.4.0.1 * Fix issue with the 1.4 tool springboarding to older releases (see [Issue #7491](https://github.com/meteor/meteor/issues/7491)) From 8ac556b993627cf06cc98565396cb27692adc33a Mon Sep 17 00:00:00 2001 From: c9s Date: Tue, 26 Jul 2016 22:17:04 +0800 Subject: [PATCH 040/688] Fix source map header --- tools/isobuild/linker.js | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/tools/isobuild/linker.js b/tools/isobuild/linker.js index d9d084dfa5..823aa584e1 100644 --- a/tools/isobuild/linker.js +++ b/tools/isobuild/linker.js @@ -1057,27 +1057,28 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, { name }); + if (includeSourceMapInstructions) { + header = SOURCE_MAP_INSTRUCTIONS_COMMENT + "\n\n" + header; + } + + // Bias the source map by the length of the header without + // (fully) parsing and re-serializing it. (We used to do this + // with the source-map library, but it was incredibly slow, + // accounting for over half of bundling time.) It would be nice + // if we could use "index maps" for this (the 'sections' key), + // as that would let us avoid even JSON-parsing the source map, + // but that doesn't seem to be supported by Firefox yet. + if (header.charAt(header.length - 1) !== "\n") { + // make sure it's a whole number of lines + header += "\n"; + } + var headerLines = header.split('\n').length - 1; + var headerContent = (new Array(headerLines + 1).join(';')); + return _.map(prelinkedFiles, function (file) { if (file.sourceMap) { - if (includeSourceMapInstructions) { - header = SOURCE_MAP_INSTRUCTIONS_COMMENT + "\n\n" + header; - } - - // Bias the source map by the length of the header without - // (fully) parsing and re-serializing it. (We used to do this - // with the source-map library, but it was incredibly slow, - // accounting for over half of bundling time.) It would be nice - // if we could use "index maps" for this (the 'sections' key), - // as that would let us avoid even JSON-parsing the source map, - // but that doesn't seem to be supported by Firefox yet. - if (header.charAt(header.length - 1) !== "\n") { - // make sure it's a whole number of lines - header += "\n"; - } - var headerLines = header.split('\n').length - 1; var sourceMap = file.sourceMap; - sourceMap.mappings = (new Array(headerLines + 1).join(';')) + - sourceMap.mappings; + sourceMap.mappings = headerContent + sourceMap.mappings; return { source: header + file.source + footer, sourcePath: file.sourcePath, From e4dd8684b1ead95bfa7d5668c01e2a4208909168 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Aug 2016 22:51:00 -0700 Subject: [PATCH 041/688] CoffeeScript compiling badly interacts with Babel. --- packages/coffeescript-test-helper/exporting.coffee | 14 ++++++++++++++ packages/coffeescript-test-helper/package.js | 2 ++ packages/coffeescript/tests/coffeescript_tests.js | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/packages/coffeescript-test-helper/exporting.coffee b/packages/coffeescript-test-helper/exporting.coffee index eb75de9f7d..93e4873187 100644 --- a/packages/coffeescript-test-helper/exporting.coffee +++ b/packages/coffeescript-test-helper/exporting.coffee @@ -1 +1,15 @@ COFFEESCRIPT_EXPORTED = 123 +COFFEESCRIPT_EXPORTED_ONE_MORE = 234 + +# Having backticks in the code is required to trigger Babel processing +# the file and re-wrapping the list of defined variables. +`COFFEESCRIPT_EXPORTED_WITH_BACKTICKS = 345` + +# Defining a class which extends a new class forces CoffeeScript +# to define an "extend" function, which then in turn forces Babel +# to re-wrap the list of defined variables so that each is defined +# in its own line. + +class TestClass + +class ClassExtending extends TestClass diff --git a/packages/coffeescript-test-helper/package.js b/packages/coffeescript-test-helper/package.js index ec5f594029..4d8549bdb8 100644 --- a/packages/coffeescript-test-helper/package.js +++ b/packages/coffeescript-test-helper/package.js @@ -6,5 +6,7 @@ Package.describe({ Package.onUse(function (api) { api.use('coffeescript', ['client', 'server']); api.export('COFFEESCRIPT_EXPORTED'); + api.export('COFFEESCRIPT_EXPORTED_ONE_MORE'); + api.export('COFFEESCRIPT_EXPORTED_WITH_BACKTICKS'); api.addFiles("exporting.coffee", ['client', 'server']); }); diff --git a/packages/coffeescript/tests/coffeescript_tests.js b/packages/coffeescript/tests/coffeescript_tests.js index 033d7f9082..df127d2cc3 100644 --- a/packages/coffeescript/tests/coffeescript_tests.js +++ b/packages/coffeescript/tests/coffeescript_tests.js @@ -9,4 +9,8 @@ Tinytest.add("literate coffeescript - presence", function(test) { Tinytest.add("coffeescript - exported variable", function(test) { test.equal(COFFEESCRIPT_EXPORTED, 123); test.equal(Package['coffeescript-test-helper'].COFFEESCRIPT_EXPORTED, 123); + test.equal(COFFEESCRIPT_EXPORTED_ONE_MORE, 234); + test.equal(Package['coffeescript-test-helper'].COFFEESCRIPT_EXPORTED_ONE_MORE, 234); + test.equal(COFFEESCRIPT_EXPORTED_WITH_BACKTICKS, 345); + test.equal(Package['coffeescript-test-helper'].COFFEESCRIPT_EXPORTED_WITH_BACKTICKS, 345); }); From 4c31d680876001b2dd23d020153b91578b783e79 Mon Sep 17 00:00:00 2001 From: Benedikt Huss Date: Sun, 31 Jul 2016 13:04:36 +0200 Subject: [PATCH 042/688] Password reset tokens have now a default expiration time of 3 days --- packages/accounts-base/accounts_common.js | 13 +++- packages/accounts-base/accounts_server.js | 36 ++++++++++ packages/accounts-password/password_server.js | 5 ++ packages/accounts-password/password_tests.js | 69 +++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/packages/accounts-base/accounts_common.js b/packages/accounts-base/accounts_common.js index 8282789cfa..aea362c462 100644 --- a/packages/accounts-base/accounts_common.js +++ b/packages/accounts-base/accounts_common.js @@ -83,6 +83,9 @@ export class AccountsCommon { // - loginExpirationInDays {Number} // Number of days since login until a user is logged out (login token // expires). + // - passwordResetTokenExpirationInDays {Number} + // Number of days since password reset token creation until the + // token cannt be used any longer (password reset token expires). /** * @summary Set global accounts options. @@ -93,6 +96,7 @@ export class AccountsCommon { * @param {String | Function} options.restrictCreationByEmailDomain If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: `Accounts.config({ restrictCreationByEmailDomain: 'school.edu' })`. * @param {Number} options.loginExpirationInDays The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to `null` to disable login expiration. * @param {String} options.oauthSecretKey When using the `oauth-encryption` package, the 16 byte key using to encrypt sensitive account credentials in the database, encoded in base64. This option may only be specifed on the server. See packages/oauth-encryption/README.md for details. + * @param {Number} options.passwordResetTokenExpirationInDays The number of days from when a link to reset password is sent until token expires and user can't reset password with the link anymore. Defaults to 3. */ config(options) { var self = this; @@ -125,7 +129,7 @@ export class AccountsCommon { // validate option keys var VALID_KEYS = ["sendVerificationEmail", "forbidClientAccountCreation", - "restrictCreationByEmailDomain", "loginExpirationInDays"]; + "restrictCreationByEmailDomain", "loginExpirationInDays", "passwordResetTokenExpirationInDays"]; _.each(_.keys(options), function (key) { if (!_.contains(VALID_KEYS, key)) { throw new Error("Accounts.config: Invalid key: " + key); @@ -208,6 +212,11 @@ export class AccountsCommon { DEFAULT_LOGIN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000; } + _getPasswordResetTokenLifetimeMs() { + return (this._options.passwordResetTokenExpirationInDays || + DEFAULT_PASSWORD_RESET_TOKEN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000; + } + _tokenExpiration(when) { // We pass when through the Date constructor for backwards compatibility; // `when` used to be a number. @@ -248,6 +257,8 @@ Meteor.user = function () { // how long (in days) until a login token expires var DEFAULT_LOGIN_EXPIRATION_DAYS = 90; +// how long (in days) until reset password token expires +var DEFAULT_PASSWORD_RESET_TOKEN_EXPIRATION_DAYS = 3; // Clients don't try to auto-login with a token that is going to expire within // .1 * DEFAULT_LOGIN_EXPIRATION_DAYS, capped at MIN_TOKEN_LIFETIME_CAP_SECS. // Tries to avoid abrupt disconnects from expiring tokens. diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index b81dd40482..76f68048b6 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -1115,6 +1115,41 @@ Ap._expireTokens = function (oldestValidDate, userId) { // expired tokens. }; +// Deletes expired password reset tokens from the database. +// +// Exported for tests. Also, the arguments are only used by +// tests. oldestValidDate is simulate expiring tokens without waiting +// for them to actually expire. userId is used by tests to only expire +// tokens for the test user. +Ap._expirePasswordResetTokens = function (oldestValidDate, userId) { + var tokenLiftetimeMs = this. _getPasswordResetTokenLifetimeMs(); + + // when calling from a test with extra arguments, you must specify both! + if ((oldestValidDate && !userId) || (!oldestValidDate && userId)) { + throw new Error("Bad test. Must specify both oldestValidDate and userId."); + } + + oldestValidDate = oldestValidDate || + (new Date(new Date() - tokenLifetimeMs)); + var userFilter = userId ? {_id: userId} : {}; + + this.users.update(_.extend(userFilter, { + $or: [ + { "services.password.reset.when": { $lt: oldestValidDate } }, + { "services.password.reset.when": { $lt: +oldestValidDate } } + ] + }), { + $pull: { + "services.password.reset": { + $or: [ + { when: { $lt: oldestValidDate } }, + { when: { $lt: +oldestValidDate } } + ] + } + } + }, { multi: true }); +} + // @override from accounts_common.js Ap.config = function (options) { // Call the overridden implementation of the method. @@ -1135,6 +1170,7 @@ Ap.config = function (options) { function setExpireTokensInterval(accounts) { accounts.expireTokenInterval = Meteor.setInterval(function () { accounts._expireTokens(); + accounts._expirePasswordResetTokens(); }, EXPIRE_TOKENS_INTERVAL_MS); } diff --git a/packages/accounts-password/password_server.js b/packages/accounts-password/password_server.js index 0262386488..bd36804bb6 100644 --- a/packages/accounts-password/password_server.js +++ b/packages/accounts-password/password_server.js @@ -664,6 +664,11 @@ Meteor.methods({resetPassword: function (token, newPassword) { "services.password.reset.token": token}); if (!user) throw new Meteor.Error(403, "Token expired"); + var when = user.services.password.reset.when; + var tokenLifetimeMs = Accounts._getPasswordResetTokenLifetimeMs(); + var currentTimeMs = Date.now(); + if ((currentTimeMs - when) > tokenLifetimeMs) + throw new Meteor.Error(403, "Token expired"); var email = user.services.password.reset.email; if (!_.include(_.pluck(user.emails || [], 'address'), email)) return { diff --git a/packages/accounts-password/password_tests.js b/packages/accounts-password/password_tests.js index b6f831d6f6..248ac13fbf 100644 --- a/packages/accounts-password/password_tests.js +++ b/packages/accounts-password/password_tests.js @@ -1392,6 +1392,75 @@ if (Meteor.isServer) (function () { }, /Incorrect password/); }); + Tinytest.add( + 'passwords - reset password should work when token is not expired', + function (test, onComplete) { + var username = Random.id(); + var email = username + '-intercept@example.com'; + + var userId = Accounts.createUser({ + username: username, + email: email, + password: "old-password" + }); + + var user = Meteor.users.findOne(userId); + + Accounts.sendResetPasswordEmail(userId, email); + + var resetPasswordEmailOptions = + Meteor.call("getInterceptedEmails", email)[0]; + + var re = new RegExp(Meteor.absoluteUrl() + "#/reset-password/(\\S*)"); + var match = resetPasswordEmailOptions.text.match(re); + test.isTrue(match); + var resetPasswordToken = match[1]; + + makeTestConnection( + test, + function () { + + test.isTrue(Meteor.call("resetPassword", resetPasswordToken, "new-password")); + test.isTrue(Meteor.call("login", {user: {username: username}, password: "new-password"})); + + onComplete(); + }); + }); + + Tinytest.add( + 'passwords - reset password should not work when token is expired', + function (test) { + var username = Random.id(); + var email = username + '-intercept@example.com'; + + var userId = Accounts.createUser({ + username: username, + email: email, + password: "old-password" + }); + + var user = Meteor.users.findOne(userId); + + Accounts.sendResetPasswordEmail(userId, email); + + var resetPasswordEmailOptions = + Meteor.call("getInterceptedEmails", email)[0]; + + var re = new RegExp(Meteor.absoluteUrl() + "#/reset-password/(\\S*)"); + var match = resetPasswordEmailOptions.text.match(re); + test.isTrue(match); + var resetPasswordToken = match[1]; + + Meteor.users.update(userId, {$set: {"services.password.reset.when": new Date(Date.now() + -5 * 24 * 3600 * 1000) }}); + + test.throws(function () { + Meteor.call("resetPassword", resetPasswordToken, "new-password"); + }, /Token expired/); + test.throws(function () { + Meteor.call("login", {user: {username: username}, password: "new-password"}); + }, /Incorrect password/); + }); + // We should be able to change the username Tinytest.add("passwords - change username", function (test) { var username = Random.id(); From 36afd7f5c3d3ccb36f1002095d1eca8112f69215 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 15:18:34 -0400 Subject: [PATCH 043/688] Defend global.Promise against misbehaving polyfills. --- tools/tool-env/install-promise.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/tools/tool-env/install-promise.js b/tools/tool-env/install-promise.js index dc78ea6661..10dee1cf07 100644 --- a/tools/tool-env/install-promise.js +++ b/tools/tool-env/install-promise.js @@ -1,10 +1,24 @@ // Install a global ES2015-compliant Promise constructor that knows how to // run all its callbacks in Fibers. -var Promise = global.Promise = global.Promise || +var Promise = global.Promise || require("promise/lib/es6-extensions"); -require("meteor-promise").makeCompatible( - Promise, - require("fibers") -); +function makeCompatible(newPromise) { + require("meteor-promise").makeCompatible( + newPromise, + require("fibers") + ); +} + +makeCompatible(Promise); + +Object.defineProperty(global, "Promise", { + get: function () { + return Promise; + }, + + // Make the new Promise compatible with Fibers, but do not allow further + // modifications to global.Promise, e.g. by misbehaving polyfills. + set: makeCompatible +}); From 2de0fb59ef9023923ed4d0637808de66181e9bd5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 15:19:31 -0400 Subject: [PATCH 044/688] Make sure self-tests have a consistent runtime environment. --- tools/tool-testing/selftest.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/tool-testing/selftest.js b/tools/tool-testing/selftest.js index 49d5e7445a..15fe71bd31 100644 --- a/tools/tool-testing/selftest.js +++ b/tools/tool-testing/selftest.js @@ -27,6 +27,8 @@ var release = require('../packaging/release.js'); var projectContextModule = require('../project-context.js'); var upgraders = require('../upgraders.js'); +require("../tool-env/install-runtime.js"); + try { var phantomjs = require('phantomjs-prebuilt'); } catch (e) { From 1d5ca820df83795aa16ebd18e96a2ae76ed404c8 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 15:21:16 -0400 Subject: [PATCH 045/688] Don't swallow unexpected errors when checking for phantomjs-prebuilt. --- tools/tool-testing/selftest.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/tool-testing/selftest.js b/tools/tool-testing/selftest.js index 15fe71bd31..c2ae7feb44 100644 --- a/tools/tool-testing/selftest.js +++ b/tools/tool-testing/selftest.js @@ -30,7 +30,7 @@ var upgraders = require('../upgraders.js'); require("../tool-env/install-runtime.js"); try { - var phantomjs = require('phantomjs-prebuilt'); + var phantomPath = require.resolve('phantomjs-prebuilt'); } catch (e) { throw new Error([ "Please install PhantomJS by running the following command:", @@ -42,6 +42,8 @@ try { ].join("\n")); } +var phantomjs = require(phantomPath); + // To allow long stack traces that cross async boundaries require('longjohn'); From a617ddaec288be4c77a3ff753b1e3f4dc2d58e2d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 15:50:18 -0400 Subject: [PATCH 046/688] Add node-gyp and node-pre-gyp to server node_modules. This will help with running `npm rebuild` in bundle/programs/server, fixing problems like #7568. --- scripts/dev-bundle-server-package.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/dev-bundle-server-package.js b/scripts/dev-bundle-server-package.js index 6c03d52c98..c4641e5125 100644 --- a/scripts/dev-bundle-server-package.js +++ b/scripts/dev-bundle-server-package.js @@ -9,6 +9,8 @@ var packageJson = { // Version is not important but is needed to prevent warnings. version: "0.0.0", dependencies: { + "node-gyp": "3.4.0", + "node-pre-gyp": "0.6.29", "meteor-promise": "0.7.2", fibers: "1.0.13", promise: "7.1.1", From 83b0d901807949e3fb4e733d2ab895f9322e7b40 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 11:26:44 -0400 Subject: [PATCH 047/688] Fix multi-line input to `meteor shell`. There is unfortunately no way to access the special Recoverable constructor defined in node/lib/repl.js unless we temporarily use the defaultEval function, trigger a recoverable error, and capture its .constructor property. Fortunately we are that clever. Fixes #7504. --- tools/static-assets/server/shell-server.js | 82 ++++++++++++++++++++-- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/tools/static-assets/server/shell-server.js b/tools/static-assets/server/shell-server.js index 3e93047ab2..3f2c0e63be 100644 --- a/tools/static-assets/server/shell-server.js +++ b/tools/static-assets/server/shell-server.js @@ -176,7 +176,8 @@ Sp.onConnection = function onConnection(socket) { delete options.key; if (options.evaluateAndExit) { - evalCommand( + evalCommand.call( + Object.create(null), // Dummy repl object without ._RecoverableError. "(" + options.evaluateAndExit.command + ")", null, // evalCommand ignores the context parameter, anyway options.evaluateAndExit.filename || "", @@ -202,8 +203,7 @@ Sp.onConnection = function onConnection(socket) { // Immutable options. _.extend(options, { input: replInputSocket, - output: socket, - eval: evalCommand + output: socket }); // Overridable options. @@ -316,6 +316,26 @@ Sp.startREPL = function startREPL(options) { process.exit(0); } }); + + // Trigger one recoverable error using the default eval function, just + // to capture the Recoverable error constructor, so that our custom + // evalCommand function can wrap recoverable errors properly. + repl.eval( + "{", null, "", + function (error) { + // Capture the Recoverable error constructor. + repl._RecoverableError = error && error.constructor; + + // Now set repl.eval to the actual evalCommand function that we want + // to use, bound to repl._domain if necessary. + repl.eval = repl._domain + ? repl._domain.bind(evalCommand) + : evalCommand; + + // Terminate the partial evaluation of the { command. + repl.commands["break"].action.call(repl); + } + ); }; function getInfoFile(shellDir) { @@ -346,6 +366,21 @@ function getTerminalWidth() { var evalCommandPromise = Promise.resolve(); function evalCommand(command, context, filename, callback) { + var repl = this; + + function finish(error, result) { + if (error) { + if (repl._RecoverableError && + isRecoverableError(error, repl)) { + callback(new repl._RecoverableError(error)); + } else { + callback(error); + } + } else { + callback(null, result); + } + } + if (Package.ecmascript) { var noParens = stripParens(command); if (noParens !== command) { @@ -367,7 +402,7 @@ function evalCommand(command, context, filename, callback) { try { command = Package.ecmascript.ECMAScript.compileForShell(command); } catch (error) { - callback(error); + finish(error); return; } } @@ -378,13 +413,13 @@ function evalCommand(command, context, filename, callback) { displayErrors: false }); } catch (parseError) { - callback(parseError); + finish(parseError); return; } evalCommandPromise.then(function () { - callback(null, script.runInThisContext()); - }).catch(callback); + finish(null, script.runInThisContext()); + }).catch(finish); } function stripParens(command) { @@ -395,6 +430,39 @@ function stripParens(command) { return command; } +// The bailOnIllegalToken and isRecoverableError functions are taken from +// https://github.com/nodejs/node/blob/c9e670ea2a/lib/repl.js#L1227-L1253 +function bailOnIllegalToken(parser) { + return parser._literal === null && + ! parser.blockComment && + ! parser.regExpLiteral; +} + +// If the error is that we've unexpectedly ended the input, +// then let the user try to recover by adding more input. +function isRecoverableError(e, repl) { + if (e && e.name === 'SyntaxError') { + var message = e.message; + if (message === 'Unterminated template literal' || + message === 'Missing } in template expression') { + repl._inTemplateLiteral = true; + return true; + } + + if (message.startsWith('Unexpected end of input') || + message.startsWith('missing ) after argument list') || + message.startsWith('Unexpected token')) { + return true; + } + + if (message === 'Invalid or unexpected token') { + return ! bailOnIllegalToken(repl.lineParser); + } + } + + return false; +} + // This function allows a persistent history of shell commands to be saved // to and loaded from .meteor/local/shell-history. Sp.initializeHistory = function initializeHistory() { From 08f14ef1a25287aa341d5c5b9d55ec7d7571f320 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 11:58:51 -0400 Subject: [PATCH 048/688] Add a basic app template for testing `meteor shell`. --- tools/tests/apps/shell/.gitignore | 1 + .../apps/shell/.meteor/.finished-upgraders | 14 ++++ tools/tests/apps/shell/.meteor/.gitignore | 1 + tools/tests/apps/shell/.meteor/.id | 7 ++ tools/tests/apps/shell/.meteor/packages | 21 ++++++ tools/tests/apps/shell/.meteor/platforms | 2 + tools/tests/apps/shell/.meteor/release | 1 + tools/tests/apps/shell/.meteor/versions | 69 +++++++++++++++++++ tools/tests/apps/shell/client/main.css | 1 + tools/tests/apps/shell/client/main.html | 25 +++++++ tools/tests/apps/shell/client/main.js | 22 ++++++ tools/tests/apps/shell/package.json | 10 +++ tools/tests/apps/shell/server/main.js | 5 ++ 13 files changed, 179 insertions(+) create mode 100644 tools/tests/apps/shell/.gitignore create mode 100644 tools/tests/apps/shell/.meteor/.finished-upgraders create mode 100644 tools/tests/apps/shell/.meteor/.gitignore create mode 100644 tools/tests/apps/shell/.meteor/.id create mode 100644 tools/tests/apps/shell/.meteor/packages create mode 100644 tools/tests/apps/shell/.meteor/platforms create mode 100644 tools/tests/apps/shell/.meteor/release create mode 100644 tools/tests/apps/shell/.meteor/versions create mode 100644 tools/tests/apps/shell/client/main.css create mode 100644 tools/tests/apps/shell/client/main.html create mode 100644 tools/tests/apps/shell/client/main.js create mode 100644 tools/tests/apps/shell/package.json create mode 100644 tools/tests/apps/shell/server/main.js diff --git a/tools/tests/apps/shell/.gitignore b/tools/tests/apps/shell/.gitignore new file mode 100644 index 0000000000..40b878db5b --- /dev/null +++ b/tools/tests/apps/shell/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/tools/tests/apps/shell/.meteor/.finished-upgraders b/tools/tests/apps/shell/.meteor/.finished-upgraders new file mode 100644 index 0000000000..11fc14e301 --- /dev/null +++ b/tools/tests/apps/shell/.meteor/.finished-upgraders @@ -0,0 +1,14 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link diff --git a/tools/tests/apps/shell/.meteor/.gitignore b/tools/tests/apps/shell/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/tests/apps/shell/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/shell/.meteor/.id b/tools/tests/apps/shell/.meteor/.id new file mode 100644 index 0000000000..3f3cf63ad1 --- /dev/null +++ b/tools/tests/apps/shell/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +5tjd8d18ck7qdfgmbjb diff --git a/tools/tests/apps/shell/.meteor/packages b/tools/tests/apps/shell/.meteor/packages new file mode 100644 index 0000000000..d4c8001f20 --- /dev/null +++ b/tools/tests/apps/shell/.meteor/packages @@ -0,0 +1,21 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +meteor-base # Packages every Meteor app needs to have +mobile-experience # Packages for a great mobile UX +mongo # The database Meteor supports right now +blaze-html-templates # Compile .html files into Meteor Blaze views +reactive-var # Reactive variable for tracker +jquery # Helpful client-side library +tracker # Meteor's client-side reactive programming library + +standard-minifier-css # CSS minifier run for production mode +standard-minifier-js # JS minifier run for production mode +es5-shim # ECMAScript 5 compatibility for older browsers. +ecmascript # Enable ECMAScript2015+ syntax in app code + +autopublish # Publish all data to the clients (for prototyping) +insecure # Allow all DB writes from clients (for prototyping) diff --git a/tools/tests/apps/shell/.meteor/platforms b/tools/tests/apps/shell/.meteor/platforms new file mode 100644 index 0000000000..efeba1b50c --- /dev/null +++ b/tools/tests/apps/shell/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/tools/tests/apps/shell/.meteor/release b/tools/tests/apps/shell/.meteor/release new file mode 100644 index 0000000000..621e94f0ec --- /dev/null +++ b/tools/tests/apps/shell/.meteor/release @@ -0,0 +1 @@ +none diff --git a/tools/tests/apps/shell/.meteor/versions b/tools/tests/apps/shell/.meteor/versions new file mode 100644 index 0000000000..40d32caaa2 --- /dev/null +++ b/tools/tests/apps/shell/.meteor/versions @@ -0,0 +1,69 @@ +allow-deny@1.0.5 +autopublish@1.0.7 +autoupdate@1.3.11 +babel-compiler@6.9.0 +babel-runtime@0.1.10 +base64@1.0.9 +binary-heap@1.0.9 +blaze@2.1.8 +blaze-html-templates@1.0.4 +blaze-tools@1.0.9 +boilerplate-generator@1.0.9 +caching-compiler@1.1.6 +caching-html-compiler@1.0.6 +callback-hook@1.0.9 +check@1.2.3 +ddp@1.2.5 +ddp-client@1.3.0 +ddp-common@1.2.6 +ddp-server@1.3.9 +deps@1.0.12 +diff-sequence@1.0.6 +ecmascript@0.5.7 +ecmascript-runtime@0.3.12 +ejson@1.0.12 +es5-shim@4.6.13 +fastclick@1.0.12 +geojson-utils@1.0.9 +hot-code-push@1.0.4 +html-tools@1.0.10 +htmljs@1.0.10 +http@1.2.8 +id-map@1.0.8 +insecure@1.0.7 +jquery@1.11.9 +launch-screen@1.0.12 +livedata@1.0.18 +logging@1.1.14 +meteor@1.2.16 +meteor-base@1.0.4 +minifier-css@1.2.13 +minifier-js@1.2.13 +minimongo@1.0.17 +mobile-experience@1.0.4 +mobile-status-bar@1.0.12 +modules@0.7.5 +modules-runtime@0.7.5 +mongo@1.1.10 +mongo-id@1.0.5 +npm-mongo@1.5.45 +observe-sequence@1.0.12 +ordered-dict@1.0.8 +promise@0.8.3 +random@1.0.10 +reactive-var@1.0.10 +reload@1.1.10 +retry@1.0.8 +routepolicy@1.0.11 +spacebars@1.0.12 +spacebars-compiler@1.0.12 +standard-minifier-css@1.1.8 +standard-minifier-js@1.1.8 +templating@1.2.13 +templating-tools@1.0.4 +tracker@1.1.0 +ui@1.0.11 +underscore@1.0.9 +url@1.0.10 +webapp@1.3.10 +webapp-hashing@1.0.9 diff --git a/tools/tests/apps/shell/client/main.css b/tools/tests/apps/shell/client/main.css new file mode 100644 index 0000000000..b6b4052b43 --- /dev/null +++ b/tools/tests/apps/shell/client/main.css @@ -0,0 +1 @@ +/* CSS declarations go here */ diff --git a/tools/tests/apps/shell/client/main.html b/tools/tests/apps/shell/client/main.html new file mode 100644 index 0000000000..c9a56af2fe --- /dev/null +++ b/tools/tests/apps/shell/client/main.html @@ -0,0 +1,25 @@ + + shell + + + +

Welcome to Meteor!

+ + {{> hello}} + {{> info}} + + + + + diff --git a/tools/tests/apps/shell/client/main.js b/tools/tests/apps/shell/client/main.js new file mode 100644 index 0000000000..ecb3282a2f --- /dev/null +++ b/tools/tests/apps/shell/client/main.js @@ -0,0 +1,22 @@ +import { Template } from 'meteor/templating'; +import { ReactiveVar } from 'meteor/reactive-var'; + +import './main.html'; + +Template.hello.onCreated(function helloOnCreated() { + // counter starts at 0 + this.counter = new ReactiveVar(0); +}); + +Template.hello.helpers({ + counter() { + return Template.instance().counter.get(); + }, +}); + +Template.hello.events({ + 'click button'(event, instance) { + // increment the counter when button is clicked + instance.counter.set(instance.counter.get() + 1); + }, +}); diff --git a/tools/tests/apps/shell/package.json b/tools/tests/apps/shell/package.json new file mode 100644 index 0000000000..eaa0f0bc14 --- /dev/null +++ b/tools/tests/apps/shell/package.json @@ -0,0 +1,10 @@ +{ + "name": "shell", + "private": true, + "scripts": { + "start": "meteor run" + }, + "dependencies": { + "meteor-node-stubs": "~0.2.0" + } +} diff --git a/tools/tests/apps/shell/server/main.js b/tools/tests/apps/shell/server/main.js new file mode 100644 index 0000000000..31a9e0e2d6 --- /dev/null +++ b/tools/tests/apps/shell/server/main.js @@ -0,0 +1,5 @@ +import { Meteor } from 'meteor/meteor'; + +Meteor.startup(() => { + // code to run on server at startup +}); From 44cf6bbe4d72c3ae72fc11e50c97fef0c9ab73fe Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 14:13:28 -0400 Subject: [PATCH 049/688] Add some basic self-tests of `meteor shell`. Related to #7504. --- tools/tests/apps/shell/server/main.js | 2 +- tools/tests/shell-tests.js | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tools/tests/shell-tests.js diff --git a/tools/tests/apps/shell/server/main.js b/tools/tests/apps/shell/server/main.js index 31a9e0e2d6..b0dbc0ed81 100644 --- a/tools/tests/apps/shell/server/main.js +++ b/tools/tests/apps/shell/server/main.js @@ -1,5 +1,5 @@ import { Meteor } from 'meteor/meteor'; Meteor.startup(() => { - // code to run on server at startup + Meteor.checkMeFromShell = "oky dok"; }); diff --git a/tools/tests/shell-tests.js b/tools/tests/shell-tests.js new file mode 100644 index 0000000000..c7f26e6b4f --- /dev/null +++ b/tools/tests/shell-tests.js @@ -0,0 +1,36 @@ +var selftest = require('../tool-testing/selftest.js'); +var Sandbox = selftest.Sandbox; + +selftest.define("meteor shell", function () { + var s = new Sandbox(); + s.createApp("meteor-shell-test", "shell"); + s.cd("meteor-shell-test"); + + var server = s.run("run", "--once"); + server.waitSecs(45); + server.match("App running at"); + + var shell = s.run("shell"); + // First try a simple one-line expression. + shell.write("{server:Meteor.isServer}\n"); + shell.proc.stdin.end(); + shell.match('{"server":true}'); + + shell = s.run("shell"); + // Now try with a bunch of newlines in the input. + shell.write("500+\n4000\n+60\n\n+\n7\n"); + shell.proc.stdin.end(); + shell.match("4567"); + + shell = s.run("shell"); + // Now use the shell to make the server output something. + shell.write('console.log("oyez")\n'); + shell.proc.stdin.end(); + server.match("oyez"); + + shell = s.run("shell"); + // Now check something set by the test app. + shell.write('Meteor.checkMeFromShell\n'); + shell.proc.stdin.end(); + shell.match("oky dok"); +}); From 7ece1e5a28a743be47659a08374fd49a938f2838 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 15:58:36 -0400 Subject: [PATCH 050/688] Bump $BUNDLE_VERSION to 4.2.3 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index fb80725cda..b76e3b0bad 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.2 +BUNDLE_VERSION=4.2.3 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From 7363d9c0be0c17f5d391733a91d78d46b987afaa Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 3 Aug 2016 16:33:22 -0400 Subject: [PATCH 051/688] Upgrade uglify-js to version 2.7.0. This version still doesn't support many ES2015 features, but we might as well use the latest stable version. --- .../.npm/package/npm-shrinkwrap.json | 142 +++++++++++------- packages/minifier-js/package.js | 6 +- 2 files changed, 91 insertions(+), 57 deletions(-) diff --git a/packages/minifier-js/.npm/package/npm-shrinkwrap.json b/packages/minifier-js/.npm/package/npm-shrinkwrap.json index 5f0105ed20..31a74fb7c5 100644 --- a/packages/minifier-js/.npm/package/npm-shrinkwrap.json +++ b/packages/minifier-js/.npm/package/npm-shrinkwrap.json @@ -1,60 +1,94 @@ { "dependencies": { + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "from": "align-text@>=0.1.3 <0.2.0" + }, + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "from": "async@>=0.2.6 <0.3.0" + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "from": "camelcase@>=1.0.2 <2.0.0" + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "from": "center-align@>=0.1.1 <0.2.0" + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "from": "cliui@>=2.1.0 <3.0.0" + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "from": "decamelize@>=1.0.0 <2.0.0" + }, + "is-buffer": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", + "from": "is-buffer@>=1.0.2 <2.0.0" + }, + "kind-of": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz", + "from": "kind-of@>=3.0.2 <4.0.0" + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "from": "lazy-cache@>=1.0.3 <2.0.0" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "from": "longest@>=1.0.1 <2.0.0" + }, + "repeat-string": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", + "from": "repeat-string@>=1.5.2 <2.0.0" + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "from": "right-align@>=0.1.1 <0.2.0" + }, + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "from": "source-map@>=0.5.1 <0.6.0" + }, "uglify-js": { - "version": "2.4.20", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.20.tgz", - "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.20.tgz", - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" - }, - "source-map": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", - "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", - "dependencies": { - "amdefine": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-0.1.0.tgz", - "from": "https://registry.npmjs.org/amdefine/-/amdefine-0.1.0.tgz" - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "from": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" - }, - "yargs": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", - "from": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", - "dependencies": { - "camelcase": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.0.2.tgz", - "from": "https://registry.npmjs.org/camelcase/-/camelcase-1.0.2.tgz" - }, - "decamelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz", - "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz" - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" - } - } - } - } + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.0.tgz", + "from": "uglify-js@2.7.0" + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "from": "uglify-to-browserify@>=1.0.0 <1.1.0" + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "from": "window-size@0.1.0" + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "from": "wordwrap@0.0.2" + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "from": "yargs@>=3.10.0 <3.11.0" } } } diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index afb5f8b6c9..b53c6ceb37 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,14 +1,14 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.13" + version: "1.2.14" }); Npm.depends({ - "uglify-js": "2.4.20", + "uglify-js": "2.7.0" }); Npm.strip({ - "uglify-js": ["test/"], + "uglify-js": ["test/"] }); Package.onUse(function (api) { From 2f6a6921b915154102f31f157cdf6f02612cf1e4 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 1 Aug 2016 12:45:09 -0400 Subject: [PATCH 052/688] Don't minify non-web .js files. Fixes #7479, #7441, and similar issues for server-only files that contain syntax supported by Node 4 but not supported by UglifyJS. --- packages/standard-minifier-js/package.js | 2 +- packages/standard-minifier-js/plugin/minify-js.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index dcab86536c..72c501e663 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.1.8', + version: '1.2.0', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/plugin/minify-js.js b/packages/standard-minifier-js/plugin/minify-js.js index 44ca1cf1c4..b9a5248826 100644 --- a/packages/standard-minifier-js/plugin/minify-js.js +++ b/packages/standard-minifier-js/plugin/minify-js.js @@ -1,5 +1,6 @@ Plugin.registerMinifier({ - extensions: ["js"] + extensions: ["js"], + archMatching: "web" }, function () { var minifier = new UglifyJSMinifier(); return minifier; From a83f6da0590a1c7500458a7ecd9d744d249747ac Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 1 Aug 2016 12:47:17 -0400 Subject: [PATCH 053/688] Don't minify non-web .css files. We shouldn't be processing .css files on the server anyway, because of a similar restriction in packages/meteor/plugin/basic-file-types.js, but it seemed wise to enforce that restriction redundantly here. --- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-css/plugin/minify-css.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index fc4129ed43..cf53e0e1c0 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.1.8', + version: '1.2.0', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-css/plugin/minify-css.js b/packages/standard-minifier-css/plugin/minify-css.js index 59925e4b82..8858d0b43a 100644 --- a/packages/standard-minifier-css/plugin/minify-css.js +++ b/packages/standard-minifier-css/plugin/minify-css.js @@ -1,7 +1,8 @@ var sourcemap = Npm.require('source-map'); Plugin.registerMinifier({ - extensions: ["css"] + extensions: ["css"], + archMatching: "web" }, function () { var minifier = new CssToolsMinifier(); return minifier; From ccaa3fc704c6710082f355d90081fd787d17aa80 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Thu, 4 Aug 2016 11:42:12 +1000 Subject: [PATCH 054/688] Update History.md --- History.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/History.md b/History.md index a3013e786e..329c3d0bd2 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,7 @@ ## v.NEXT +* Password Reset tokens now expire (after 3 days by default -- can be modified via `Accounts.config({ passwordResetTokenExpirationInDays: ...}`). [PR #7534](https://github.com/meteor/meteor/pull/7534) + * The `google` package now uses the `email` scope as a mandatory field instead of the `profile` scope. The `profile` scope is still added by default if the `requestPermissions` option is not specified to maintain backward From bbc0ecc6e1203d995a07bb80a17328f3a8025d69 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Fri, 5 Aug 2016 13:46:30 +0200 Subject: [PATCH 055/688] Fix broken links in the changelog (#7588) --- History.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 329c3d0bd2..17f4a11bb6 100644 --- a/History.md +++ b/History.md @@ -14,7 +14,7 @@ accessToken in some out-of-band way. [PR #7550](https://github.com/meteor/meteor/pull/7550) * `Accounts.onLogout` gets `{ user, connection }` context in a similar fashion - to `Accounts.onLogin`. [Issue #7397](https://github.com/meteor/meteor/issue/7397) [PR #7433](https://github.com/meteor/meteor/pull/7433) + to `Accounts.onLogin`. [Issue #7397](https://github.com/meteor/meteor/issues/7397) [PR #7433](https://github.com/meteor/meteor/pull/7433) ## v1.4.0.1 @@ -149,7 +149,7 @@ invoke. Note that you must `meteor update` to 1.3.4.2 before this logic will take effect, but it will work in all app directories after updating, even those pinned to older versions. - [#7338](https://github.com/meteor/meteor/issue/7338) + [#7338](https://github.com/meteor/meteor/issues/7338) * The Meteor installer now has the ability to resume downloads, so installing Meteor on a spotty internet connection should be more From 3a662a5bfbf752e643268fc9a711d732e0663575 Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Fri, 5 Aug 2016 20:22:39 +0200 Subject: [PATCH 056/688] make commits links in changelog --- History.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 17f4a11bb6..1622ae0a66 100644 --- a/History.md +++ b/History.md @@ -72,7 +72,7 @@ * This release fixed a small bug in 1.3.5 that prevented updating apps whose `.meteor/release` files refer to releases no longer installed in - `~/.meteor/packages/meteor-tool`. 576468eae8d8dd7c1fe2fa381ac51dee5cb792cd + `~/.meteor/packages/meteor-tool`. [576468eae8d8dd7c1fe2fa381ac51dee5cb792cd](https://github.com/meteor/meteor/commit/576468eae8d8dd7c1fe2fa381ac51dee5cb792cd) ## v1.3.5 @@ -83,7 +83,7 @@ * If an app has no `package.json` file, all packages in `node_modules` will be built into the production bundle. In other words, make sure you have a `package.json` file if you want to benefit from `devDependencies` - pruning. 7b2193188fc9e297eefc841ce6035825164f0684 + pruning. [7b2193188fc9e297eefc841ce6035825164f0684](https://github.com/meteor/meteor/commit/7b2193188fc9e297eefc841ce6035825164f0684) * Binary npm dependencies of compiler plugins are now automatically rebuilt when Node/V8 versions change. @@ -118,7 +118,7 @@ `Npm.depends`) has been set to "error" instead of "warn". Note that this change does not affect `meteor npm ...` commands, which can be easily configured using `.npmrc` files or command-line flags. - https://github.com/meteor/meteor/commit/0689cae25a3e0da3615a402cdd0bec94ce8455c8 + [0689cae25a3e0da3615a402cdd0bec94ce8455c8](https://github.com/meteor/meteor/commit/0689cae25a3e0da3615a402cdd0bec94ce8455c8) ## v1.3.4.3 From 70b620511d92ae1f9c31c2bb76b4fdd4b93b4d7c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 5 Aug 2016 18:10:51 -0400 Subject: [PATCH 057/688] Fix tests for #7534. --- packages/accounts-password/password_tests.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/accounts-password/password_tests.js b/packages/accounts-password/password_tests.js index 248ac13fbf..fcabdfe8d3 100644 --- a/packages/accounts-password/password_tests.js +++ b/packages/accounts-password/password_tests.js @@ -1392,7 +1392,7 @@ if (Meteor.isServer) (function () { }, /Incorrect password/); }); - Tinytest.add( + Tinytest.addAsync( 'passwords - reset password should work when token is not expired', function (test, onComplete) { var username = Random.id(); @@ -1418,10 +1418,17 @@ if (Meteor.isServer) (function () { makeTestConnection( test, - function () { - - test.isTrue(Meteor.call("resetPassword", resetPasswordToken, "new-password")); - test.isTrue(Meteor.call("login", {user: {username: username}, password: "new-password"})); + function (clientConn) { + test.isTrue(clientConn.call( + "resetPassword", + resetPasswordToken, + "new-password" + )); + + test.isTrue(clientConn.call("login", { + user: { username }, + password: "new-password" + })); onComplete(); }); From cfa38d1de676feaa918f0e9a5c66f6097417a68a Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 6 Aug 2016 13:44:29 -0400 Subject: [PATCH 058/688] Fix call to nonexistent method buildmessage.hasMessages(). --- tools/cli/commands-packages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index d93a4b4aab..a8574a8905 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -609,7 +609,7 @@ main.registerCommand({ }); }); - if (buildmessage.hasMessages()) { + if (buildmessage.jobHasMessages()) { return 1; } From f9809c2f4b0bfbdb4c53928a694430f0d97d88dd Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 4 Aug 2016 11:03:10 -0400 Subject: [PATCH 059/688] Update History.md to reflect various changes for v1.4.1. --- History.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/History.md b/History.md index 17f4a11bb6..f15a98f77f 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,7 @@ ## v.NEXT +## v1.4.1 + * Password Reset tokens now expire (after 3 days by default -- can be modified via `Accounts.config({ passwordResetTokenExpirationInDays: ...}`). [PR #7534](https://github.com/meteor/meteor/pull/7534) * The `google` package now uses the `email` scope as a mandatory field instead @@ -16,6 +18,27 @@ * `Accounts.onLogout` gets `{ user, connection }` context in a similar fashion to `Accounts.onLogin`. [Issue #7397](https://github.com/meteor/meteor/issues/7397) [PR #7433](https://github.com/meteor/meteor/pull/7433) +* The `node-gyp` and `node-pre-gyp` tools will now be installed in + `bundle/programs/server/node_modules`, to assist with rebuilding binary + npm packages when deploying an app to Galaxy or elsewhere. + [#7571](https://github.com/meteor/meteor/pull/7571) + +* The `standard-minifier-{js,css}` packages no longer minify .js or .css + files on the server. [#7572](https://github.com/meteor/meteor/pull/7572) + +* Multi-line input to `meteor shell`, which was broken by changes to the + `repl` module in Node 4, works again. + [#7562](https://github.com/meteor/meteor/pull/7562) + +* The implementation of the command-line `meteor` tool now forbids + misbehaving polyfill libraries from overwriting `global.Promise`. + [#7569](https://github.com/meteor/meteor/pull/7569) + +* The `oauth-encryption` package no longer depends on the + `npm-node-aes-gcm` package (or any special npm packages), because the + Node 4 `crypto` library natively supports the `aes-128-gcm` algorithm. + [#7548](https://github.com/meteor/meteor/pull/7548) + ## v1.4.0.1 * Fix issue with the 1.4 tool springboarding to older releases (see [Issue #7491](https://github.com/meteor/meteor/issues/7491)) From b96a016202bdc53504d9ab04f9f2237de6fc8109 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 4 Aug 2016 11:15:32 -0400 Subject: [PATCH 060/688] Mention native package extraction in History.md. --- History.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/History.md b/History.md index f15a98f77f..e176601680 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,15 @@ ## v1.4.1 +* After Meteor packages are downloaded from Atmosphere, they will now be + extracted using native `tar` or `7z.exe` on Windows, instead of the + https://www.npmjs.com/package/tar library, for a significant performance + improvement. [#7457](https://github.com/meteor/meteor/pull/7457) + +* The progress indicator now distinguishes between downloading, + extracting, and loading newly-installed Meteor packages, instead of + lumping all of that work into a "downloading" status message. + * Password Reset tokens now expire (after 3 days by default -- can be modified via `Accounts.config({ passwordResetTokenExpirationInDays: ...}`). [PR #7534](https://github.com/meteor/meteor/pull/7534) * The `google` package now uses the `email` scope as a mandatory field instead From 760eecb1d2da9fdfc154d272bb4bcf51a67decc5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 4 Aug 2016 14:28:46 -0400 Subject: [PATCH 061/688] Include Node 4.5.0-rc.2 in the dev bundle. --- scripts/build-dev-bundle-common.sh | 2 +- scripts/generate-dev-bundle.ps1 | 4 ++-- scripts/generate-dev-bundle.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build-dev-bundle-common.sh b/scripts/build-dev-bundle-common.sh index 325f6f4994..22d3382402 100644 --- a/scripts/build-dev-bundle-common.sh +++ b/scripts/build-dev-bundle-common.sh @@ -6,7 +6,7 @@ set -u UNAME=$(uname) ARCH=$(uname -m) MONGO_VERSION=3.2.6 -NODE_VERSION=4.4.7 +NODE_VERSION=4.5.0-rc.2 NPM_VERSION=3.10.5 if [ "$UNAME" == "Linux" ] ; then diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 72d07cd59e..62a6b514f1 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -2,7 +2,7 @@ # use 32bit by default $PLATFORM = "windows_x86" $MONGO_VERSION = "3.2.6" -$NODE_VERSION = "4.4.7" +$NODE_VERSION = "4.5.0-rc.2" $NPM_VERSION = "3.10.5" $PYTHON_VERSION = "2.7.10" # For node-gyp @@ -47,7 +47,7 @@ cd "$DIR\bin" # download node # same node on 32bit vs 64bit? -$node_link = "http://nodejs.org/dist/v${NODE_VERSION}/win-x86/node.exe" +$node_link = "http://nodejs.org/download/rc/v${NODE_VERSION}/win-x86/node.exe" $webclient.DownloadFile($node_link, "$DIR\bin\node.exe") # On Windows we provide a reliable version of python.exe for use by diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 099a4a971d..b2c2d9f093 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -20,7 +20,7 @@ S3_HOST="s3.amazonaws.com/com.meteor.jenkins" # 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}" +NODE_URL="https://nodejs.org/download/rc/v${NODE_VERSION}/${NODE_TGZ}" echo "Downloading Node from ${NODE_URL}" curl "${NODE_URL}" | tar zx --strip-components 1 From 2c790c48a2787dac181dd8ae23ee4d8b155efe1b Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 4 Aug 2016 14:29:01 -0400 Subject: [PATCH 062/688] Bump $BUNDLE_VERSION to 4.2.4 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index b76e3b0bad..2dcd7d8b29 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.3 +BUNDLE_VERSION=4.2.4 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From 7faa4ba7d76bf77c2bee0a5b01bd9f13c9d873c2 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 5 Aug 2016 11:24:11 -0400 Subject: [PATCH 063/688] Revert "Include Node 4.5.0-rc.2 in the dev bundle." This reverts commit 64a9312e29ba7edd5d0ab310f873aa49b52fffc7. Although Meteor runs fine on Node 4.5.0, node-gyp doesn't know how to download libraries appropriate for RC releases, so it looks like we need to hold off on this upgrade until it's officially out. --- scripts/build-dev-bundle-common.sh | 2 +- scripts/generate-dev-bundle.ps1 | 4 ++-- scripts/generate-dev-bundle.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build-dev-bundle-common.sh b/scripts/build-dev-bundle-common.sh index 22d3382402..325f6f4994 100644 --- a/scripts/build-dev-bundle-common.sh +++ b/scripts/build-dev-bundle-common.sh @@ -6,7 +6,7 @@ set -u UNAME=$(uname) ARCH=$(uname -m) MONGO_VERSION=3.2.6 -NODE_VERSION=4.5.0-rc.2 +NODE_VERSION=4.4.7 NPM_VERSION=3.10.5 if [ "$UNAME" == "Linux" ] ; then diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 62a6b514f1..72d07cd59e 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -2,7 +2,7 @@ # use 32bit by default $PLATFORM = "windows_x86" $MONGO_VERSION = "3.2.6" -$NODE_VERSION = "4.5.0-rc.2" +$NODE_VERSION = "4.4.7" $NPM_VERSION = "3.10.5" $PYTHON_VERSION = "2.7.10" # For node-gyp @@ -47,7 +47,7 @@ cd "$DIR\bin" # download node # same node on 32bit vs 64bit? -$node_link = "http://nodejs.org/download/rc/v${NODE_VERSION}/win-x86/node.exe" +$node_link = "http://nodejs.org/dist/v${NODE_VERSION}/win-x86/node.exe" $webclient.DownloadFile($node_link, "$DIR\bin\node.exe") # On Windows we provide a reliable version of python.exe for use by diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index b2c2d9f093..099a4a971d 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -20,7 +20,7 @@ S3_HOST="s3.amazonaws.com/com.meteor.jenkins" # 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/download/rc/v${NODE_VERSION}/${NODE_TGZ}" +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 From a4a828e4c3fd30959ba1a480d61bb25347cb5283 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 5 Aug 2016 11:54:56 -0400 Subject: [PATCH 064/688] Install Node headers and libraries in dev_bundle/.node-gyp/. This gives us a reliable place for node-gyp to find the necessary headers and libraries for compiling binary packages, instead of relying on the accessibility of $HOME and/or $USERPROFILE. --- scripts/generate-dev-bundle.ps1 | 17 +++++++++++++---- scripts/generate-dev-bundle.sh | 11 ++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 72d07cd59e..6e9ec54562 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -78,10 +78,6 @@ rm -Recurse -Force "$DIR\7z" # add bin to the front of the path so we can use our own node for building $env:PATH = "${DIR}\bin;${env:PATH}" -# Make sure node-gyp knows how to find its build tools. -$env:PYTHON = "${DIR}\python\python.exe" -$env:GYP_MSVS_VERSION = "2015" - # Install the version of npm that we're actually going to expose from the # dev bundle. Note that we use npm@1.4.12 to install npm@${NPM_VERSION}. cd "${DIR}\lib" @@ -95,6 +91,19 @@ npm version cd node_modules\npm npm install node-gyp +# Make sure node-gyp knows how to find its build tools. +$env:PYTHON = "${DIR}\python\python.exe" +$env:GYP_MSVS_VERSION = "2015" +$env:HOME = "$DIR"; +$env:USERPROFILE = "$DIR"; + +# 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 +& "${DIR}\bin\node.exe" node_modules\node-gyp\bin\node-gyp.js install +$include_path = "${DIR}\.node-gyp\${NODE_VERSION}\include\node" +echo "Contents of ${include_path}:" +dir "$include_path" + # install dev-bundle-package.json # use short folder names # b for build diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 099a4a971d..e439817b2d 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -60,7 +60,7 @@ npm version # will get confused by the pre-existing modules. mkdir "${DIR}/build/npm-server-install" cd "${DIR}/build/npm-server-install" -node "${CHECKOUT_DIR}/scripts/dev-bundle-server-package.js" >package.json +node "${CHECKOUT_DIR}/scripts/dev-bundle-server-package.js" > package.json npm install npm shrinkwrap @@ -68,6 +68,15 @@ mkdir -p "${DIR}/server-lib/node_modules" # This ignores the stuff in node_modules/.bin, but that's OK. cp -R node_modules/* "${DIR}/server-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}/server-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" + mkdir -p "${DIR}/etc" mv package.json npm-shrinkwrap.json "${DIR}/etc/" From 4bdc65919df9615990b36cebba992f063fbbbdf7 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 5 Aug 2016 12:07:59 -0400 Subject: [PATCH 065/688] Set $USERPROFILE to the dev bundle directory for `meteor {node,npm}`. The node-gyp tool uses `process.env.HOME || process.env.USERPROFILE` to determine where it should install the .node-gyp directory containing Node headers and libraries, and we now preinstall that directory at dev_bundle/.node-gyp/, so (with this change) no download should be necessary. --- tools/cli/dev-bundle-bin-helpers.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/cli/dev-bundle-bin-helpers.js b/tools/cli/dev-bundle-bin-helpers.js index 5f68ef6eb1..873fa30e60 100644 --- a/tools/cli/dev-bundle-bin-helpers.js +++ b/tools/cli/dev-bundle-bin-helpers.js @@ -24,6 +24,10 @@ exports.getEnv = function (options) { var env = Object.create(process.env); + // This allows node-gyp to find Node headers and libraries in + // dev_bundle/.node-gyp. + env.USERPROFILE = devBundleDir; + var PATH = env.PATH || env.Path; if (PATH) { paths.push(PATH); From 0ae8494b819d605a02154737b2c19955b5b48129 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 5 Aug 2016 12:11:01 -0400 Subject: [PATCH 066/688] Bump $BUNDLE_VERSION to 4.2.5 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index 2dcd7d8b29..11f0d76f48 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.4 +BUNDLE_VERSION=4.2.5 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From 5b35fc5573edd9e00713b857ad22dadc3dc824f5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 8 Aug 2016 12:46:30 -0400 Subject: [PATCH 067/688] Bump npm-bcrypt version to republish for all architectures. --- packages/non-core/npm-bcrypt/.versions | 2 +- packages/non-core/npm-bcrypt/package.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/non-core/npm-bcrypt/.versions b/packages/non-core/npm-bcrypt/.versions index 6697cb762c..d755fbc0d1 100644 --- a/packages/non-core/npm-bcrypt/.versions +++ b/packages/non-core/npm-bcrypt/.versions @@ -1,3 +1,3 @@ meteor@1.1.16 -npm-bcrypt@0.8.7 +npm-bcrypt@0.8.7_1 underscore@1.0.9 diff --git a/packages/non-core/npm-bcrypt/package.js b/packages/non-core/npm-bcrypt/package.js index ecaa1f8af1..216ed15756 100644 --- a/packages/non-core/npm-bcrypt/package.js +++ b/packages/non-core/npm-bcrypt/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Wrapper around the bcrypt npm package", - version: '0.8.7', + version: '0.8.7_1', documentation: null }); From 0d4cf0236190bba18edd2217d65e5cdcd92a27bd Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 8 Aug 2016 12:46:47 -0400 Subject: [PATCH 068/688] Add version constraints for all dependencies of accounts-password. This is necessary to allow publishing accounts-password independently of a Meteor release. Note that the npm-bcrypt version has been bumped to 0.8.7_1. --- packages/accounts-password/package.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 01ea4278df..34671df504 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,27 +1,27 @@ Package.describe({ summary: "Password support for accounts", - version: "1.2.12" + version: "1.2.13" }); Package.onUse(function(api) { - api.use('npm-bcrypt@=0.8.7'); + api.use('npm-bcrypt@=0.8.7_1'); api.use([ - 'accounts-base', - 'srp', - 'sha', - 'ejson', - 'ddp' + 'accounts-base@1.2.9', + 'srp@1.0.9', + 'sha@1.0.8', + 'ejson@1.0.12', + 'ddp@1.2.5' ], ['client', 'server']); // Export Accounts (etc) to packages using this one. - api.imply('accounts-base', ['client', 'server']); + api.imply('accounts-base@1.2.9', ['client', 'server']); - api.use('email', ['server']); - api.use('random', ['server']); - api.use('check'); - api.use('underscore'); - api.use('ecmascript'); + api.use('email@1.1.16', ['server']); + api.use('random@1.0.10', ['server']); + api.use('check@1.2.3'); + api.use('underscore@1.0.9'); + api.use('ecmascript@0.5.7'); api.addFiles('email_templates.js', 'server'); api.addFiles('password_server.js', 'server'); From cb587f6145af3f6362bb6a0fd174abe704680ec8 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 8 Aug 2016 18:38:15 -0400 Subject: [PATCH 069/688] Upgrade meteor-ecmascript-runtime to 0.2.8. Most notably, this version reuses global.Symbol when possible. --- .../.npm/package/npm-shrinkwrap.json | 18 ++++++++---------- packages/ecmascript-runtime/package.js | 10 +++++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json b/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json index b6abbda7be..3a25c59713 100644 --- a/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json +++ b/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json @@ -1,16 +1,14 @@ { "dependencies": { + "core-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.1.tgz", + "from": "core-js@1.2.1" + }, "meteor-ecmascript-runtime": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/meteor-ecmascript-runtime/-/meteor-ecmascript-runtime-0.2.6.tgz", - "from": "https://registry.npmjs.org/meteor-ecmascript-runtime/-/meteor-ecmascript-runtime-0.2.6.tgz", - "dependencies": { - "core-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.1.tgz", - "from": "https://registry.npmjs.org/core-js/-/core-js-1.2.1.tgz" - } - } + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/meteor-ecmascript-runtime/-/meteor-ecmascript-runtime-0.2.8.tgz", + "from": "meteor-ecmascript-runtime@0.2.8" } } } diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index b014f46c7d..747da9d95b 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,23 +1,23 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.12", + version: "0.3.13", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" }); Npm.depends({ - "meteor-ecmascript-runtime": "0.2.6", + "meteor-ecmascript-runtime": "0.2.8", }); Package.onUse(function(api) { // If the es5-shim package is installed, make sure it loads before // ecmascript-runtime, since ecmascript-runtime uses some ES5 APIs like // Object.defineProperties that are buggy in older browsers. - api.use("es5-shim", { weak: true }); + api.use("es5-shim@4.6.13", { weak: true }); - api.use("modules"); - api.use("promise"); + api.use("modules@0.7.5"); + api.use("promise@0.8.3"); api.mainModule("runtime.js"); From a912eed990002824b3407ffa49cb4b9393539fe0 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 8 Aug 2016 19:35:11 -0400 Subject: [PATCH 070/688] Fix accidental stripping of @scoped npm packages. (#7609) The previous code did not accommodate the possibility that `meteorNpm.getProdPackageNames` might return a package name that contained one or more `/` characters. Fixes #7579. --- tools/isobuild/bundler.js | 54 ++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/tools/isobuild/bundler.js b/tools/isobuild/bundler.js index 59cab96a65..8a342eb9da 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -1885,7 +1885,23 @@ class JsImage { }; if (nmd.local) { - let prodPackageNames; + const prodPackageTree = Object.create(null); + const complete = Symbol(); + let maxPartCount = 0; + + Object.keys( + meteorNpm.getProdPackageNames(nmd.sourcePath) + ).forEach(name => { + const parts = name.split("/"); + let tree = prodPackageTree; + + parts.forEach(part => { + tree = tree[part] || (tree[part] = Object.create(null)); + }); + + tree[complete] = true; + maxPartCount = Math.max(parts.length, maxPartCount); + }); // When copying a local node_modules directory, ignore any npm // package directories not in the list of production package @@ -1897,18 +1913,38 @@ class JsImage { // package's "dependencies", then every copy of that package // will be copied to the destination directory. A little bit of // overcopying vastly simplifies the job of directoryFilter. - copyOptions.directoryFilter = function (dir) { - var base = files.pathBasename(dir); - var parentBase = files.pathBasename(files.pathDirname(dir)); - if (parentBase !== "node_modules") { + copyOptions.directoryFilter = function isWithinProdPackage(dir) { + const parts = files.pathRelative(nmd.sourcePath, dir) + .split(files.pathSep); + + let start = parts.lastIndexOf("node_modules") + 1; + + if (parts.length - start > maxPartCount) { + // We're deep enough inside node_modules that it's safe to + // say we should have returned false earlier. return true; } - // Compute prodPackageNames lazily. - prodPackageNames = prodPackageNames || - meteorNpm.getProdPackageNames(nmd.sourcePath); + let tree = prodPackageTree; - return _.has(prodPackageNames, base); + for (let pos = start; pos < parts.length; ++pos) { + const part = parts[pos]; + const branch = tree[part]; + + if (! branch) { + // This dir is not prefixed by a production package name. + return false; + } + + if (branch[complete]) { + // This dir is prefixed by a complete production package name. + break; + } + + tree = branch; + } + + return true; }; } From 15684bc47e26fd3ef874d435f8d7c766cf5ab70c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 8 Aug 2016 20:44:39 -0400 Subject: [PATCH 071/688] Bump package versions for 1.4.1-beta.0 release. --- packages/accounts-base/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/less/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index a64b9a6611..ebef4319d0 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.9" + version: "1.2.10-beta.0" }); Package.onUse(function (api) { diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 7f339ed356..df8b50745c 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.3" + version: "1.2.4-beta.0" }); Package.registerBuildPlugin({ diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 252280c8be..2a87099b03 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.7', + version: '0.5.8-beta.0', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 456e9e2525..4c840c5e55 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.8" + version: "1.2.9-beta.0" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 4dd3ec78a9..6262f9481a 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.13" + version: "1.1.14-beta.0" }); Package.onUse(function(api) { diff --git a/packages/less/package.js b/packages/less/package.js index 589d8bf262..2a80110fd4 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.4', + version: '2.7.5-beta.0', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 09098a8829..015e41be53 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.4.0-1' + version: '1.4.1-beta.0' }); Package.includeTool(); diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index b53c6ceb37..3415ca840b 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14" + version: "1.2.14-beta.0" }); Npm.depends({ diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index cf53e0e1c0..4a91141576 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0', + version: '1.2.0-beta.0', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 72c501e663..6f7ee445df 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0', + version: '1.2.0-beta.0', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index e8df227b46..5199039aee 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.11', + version: '1.1.12-beta.0', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 27946df7ac..66e5953f0c 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.4" + version: "2.513.5-beta.0" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 31a8133d11..91744dab5d 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.13' + version: '1.2.14-beta.0' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index acf7469cac..4a1a61d1a0 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.0.1-rc.3", + "version": "1.4.1-beta.0", "recommended": false, "official": false, "description": "Meteor" From d15e87c82300c46c7330a5c5698a913c9275183e Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 9 Aug 2016 13:06:13 -0400 Subject: [PATCH 072/688] Fix typo in Accounts#_expirePasswordResetTokens. Follow-up to #7534. --- packages/accounts-base/accounts_server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index d9fd94cc1a..f694b3a2bb 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -1123,7 +1123,7 @@ Ap._expireTokens = function (oldestValidDate, userId) { // for them to actually expire. userId is used by tests to only expire // tokens for the test user. Ap._expirePasswordResetTokens = function (oldestValidDate, userId) { - var tokenLiftetimeMs = this. _getPasswordResetTokenLifetimeMs(); + var tokenLifetimeMs = this._getPasswordResetTokenLifetimeMs(); // when calling from a test with extra arguments, you must specify both! if ((oldestValidDate && !userId) || (!oldestValidDate && userId)) { From c8f16330121c31b0f8dfabbcc574cba654461b7c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 9 Aug 2016 13:06:13 -0400 Subject: [PATCH 073/688] Fix typo in Accounts#_expirePasswordResetTokens. Needed to add version constraints to all the dependencies in accounts-base/package.js so that I can publish it independently from a Meteor release. Follow-up to #7534. Fixes #7611. --- packages/accounts-base/accounts_server.js | 2 +- packages/accounts-base/package.js | 32 +++++++++++------------ packages/accounts-password/package.js | 6 ++--- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index d9fd94cc1a..f694b3a2bb 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -1123,7 +1123,7 @@ Ap._expireTokens = function (oldestValidDate, userId) { // for them to actually expire. userId is used by tests to only expire // tokens for the test user. Ap._expirePasswordResetTokens = function (oldestValidDate, userId) { - var tokenLiftetimeMs = this. _getPasswordResetTokenLifetimeMs(); + var tokenLifetimeMs = this._getPasswordResetTokenLifetimeMs(); // when calling from a test with extra arguments, you must specify both! if ((oldestValidDate && !userId) || (!oldestValidDate && userId)) { diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index a64b9a6611..34d5b67b59 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,39 +1,39 @@ Package.describe({ summary: "A user account system", - version: "1.2.9" + version: "1.2.10" }); Package.onUse(function (api) { - api.use('underscore', ['client', 'server']); - api.use('ecmascript', ['client', 'server']); - api.use('ddp-rate-limiter'); - api.use('localstorage', 'client'); - api.use('tracker', 'client'); - api.use('check', 'server'); - api.use('random', ['client', 'server']); - api.use('ejson', 'server'); - api.use('callback-hook', ['client', 'server']); + api.use('underscore@1.0.9', ['client', 'server']); + api.use('ecmascript@0.5.7', ['client', 'server']); + api.use('ddp-rate-limiter@1.0.5'); + api.use('localstorage@1.0.11', 'client'); + api.use('tracker@1.1.0', 'client'); + api.use('check@1.2.3', 'server'); + api.use('random@1.0.10', ['client', 'server']); + api.use('ejson@1.0.12', 'server'); + api.use('callback-hook@1.0.9', ['client', 'server']); // use unordered to work around a circular dependency // (service-configuration needs Accounts.connection) - api.use('service-configuration', ['client', 'server'], { unordered: true }); + api.use('service-configuration@1.0.10', ['client', 'server'], { unordered: true }); // needed for getting the currently logged-in user - api.use('ddp', ['client', 'server']); + api.use('ddp@1.2.5', ['client', 'server']); // need this because of the Meteor.users collection but in the future // we'd probably want to abstract this away - api.use('mongo', ['client', 'server']); + api.use('mongo@1.1.10', ['client', 'server']); // If the 'blaze' package is loaded, we'll define some helpers like // {{currentUser}}. If not, no biggie. - api.use('blaze', 'client', {weak: true}); + api.use('blaze@2.1.8', 'client', {weak: true}); // Allow us to detect 'autopublish', and publish some Meteor.users fields if // it's loaded. - api.use('autopublish', 'server', {weak: true}); + api.use('autopublish@1.0.7', 'server', {weak: true}); - api.use('oauth-encryption', 'server', {weak: true}); + api.use('oauth-encryption@1.2.0', 'server', {weak: true}); // Though this "Accounts" symbol is the only official Package export for // the accounts-base package, modules that import accounts-base will diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 34671df504..f4f8b3360e 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,13 +1,13 @@ Package.describe({ summary: "Password support for accounts", - version: "1.2.13" + version: "1.2.14" }); Package.onUse(function(api) { api.use('npm-bcrypt@=0.8.7_1'); api.use([ - 'accounts-base@1.2.9', + 'accounts-base@1.2.10', 'srp@1.0.9', 'sha@1.0.8', 'ejson@1.0.12', @@ -15,7 +15,7 @@ Package.onUse(function(api) { ], ['client', 'server']); // Export Accounts (etc) to packages using this one. - api.imply('accounts-base@1.2.9', ['client', 'server']); + api.imply('accounts-base@1.2.10', ['client', 'server']); api.use('email@1.1.16', ['server']); api.use('random@1.0.10', ['server']); From a1c35160530edb625312db718d7c36014dbf4049 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 9 Aug 2016 16:42:41 -0400 Subject: [PATCH 074/688] Use pure-JavaScript implementation for npm-bcrypt package. (#7595) According to the README, this implementation is approximately 2.7 times slower than native: https://www.npmjs.com/package/bcryptjs Apps that wish to continue using the native bcrypt package should run `meteor npm install --save bcrypt` in the root application directory, and the npm-bcrypt package will prefer that implementation. --- packages/accounts-password/package.js | 4 +- .../.npm/package/npm-shrinkwrap.json | 19 ---------- packages/non-core/npm-bcrypt/.versions | 3 -- packages/non-core/npm-bcrypt/package.js | 14 ------- packages/non-core/npm-bcrypt/wrapper.js | 1 - packages/{non-core => }/npm-bcrypt/.gitignore | 0 .../npm-bcrypt/.npm/package/.gitignore | 0 .../npm-bcrypt/.npm/package/README | 0 .../.npm/package/npm-shrinkwrap.json | 9 +++++ packages/npm-bcrypt/.versions | 5 +++ packages/npm-bcrypt/package.js | 15 ++++++++ packages/npm-bcrypt/wrapper.js | 38 +++++++++++++++++++ tools/tests/package-tests.js | 8 ---- 13 files changed, 69 insertions(+), 47 deletions(-) delete mode 100644 packages/non-core/npm-bcrypt/.npm/package/npm-shrinkwrap.json delete mode 100644 packages/non-core/npm-bcrypt/.versions delete mode 100644 packages/non-core/npm-bcrypt/package.js delete mode 100644 packages/non-core/npm-bcrypt/wrapper.js rename packages/{non-core => }/npm-bcrypt/.gitignore (100%) rename packages/{non-core => }/npm-bcrypt/.npm/package/.gitignore (100%) rename packages/{non-core => }/npm-bcrypt/.npm/package/README (100%) create mode 100644 packages/npm-bcrypt/.npm/package/npm-shrinkwrap.json create mode 100644 packages/npm-bcrypt/.versions create mode 100644 packages/npm-bcrypt/package.js create mode 100644 packages/npm-bcrypt/wrapper.js diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index f4f8b3360e..6e1e8e9dcb 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,10 +1,10 @@ Package.describe({ summary: "Password support for accounts", - version: "1.2.14" + version: "1.3.0" }); Package.onUse(function(api) { - api.use('npm-bcrypt@=0.8.7_1'); + api.use('npm-bcrypt@0.9.0', 'server'); api.use([ 'accounts-base@1.2.10', diff --git a/packages/non-core/npm-bcrypt/.npm/package/npm-shrinkwrap.json b/packages/non-core/npm-bcrypt/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index 9f8bfdb477..0000000000 --- a/packages/non-core/npm-bcrypt/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "dependencies": { - "bcrypt": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-0.8.7.tgz", - "from": "bcrypt@0.8.7" - }, - "bindings": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", - "from": "bindings@1.2.1" - }, - "nan": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz", - "from": "nan@2.3.5" - } - } -} diff --git a/packages/non-core/npm-bcrypt/.versions b/packages/non-core/npm-bcrypt/.versions deleted file mode 100644 index d755fbc0d1..0000000000 --- a/packages/non-core/npm-bcrypt/.versions +++ /dev/null @@ -1,3 +0,0 @@ -meteor@1.1.16 -npm-bcrypt@0.8.7_1 -underscore@1.0.9 diff --git a/packages/non-core/npm-bcrypt/package.js b/packages/non-core/npm-bcrypt/package.js deleted file mode 100644 index 216ed15756..0000000000 --- a/packages/non-core/npm-bcrypt/package.js +++ /dev/null @@ -1,14 +0,0 @@ -Package.describe({ - summary: "Wrapper around the bcrypt npm package", - version: '0.8.7_1', - documentation: null -}); - -Npm.depends({ - bcrypt: '0.8.7' -}); - -Package.onUse(function (api) { - api.export('NpmModuleBcrypt', 'server'); - api.addFiles('wrapper.js', 'server'); -}); diff --git a/packages/non-core/npm-bcrypt/wrapper.js b/packages/non-core/npm-bcrypt/wrapper.js deleted file mode 100644 index afff6278ff..0000000000 --- a/packages/non-core/npm-bcrypt/wrapper.js +++ /dev/null @@ -1 +0,0 @@ -NpmModuleBcrypt = Npm.require('bcrypt'); diff --git a/packages/non-core/npm-bcrypt/.gitignore b/packages/npm-bcrypt/.gitignore similarity index 100% rename from packages/non-core/npm-bcrypt/.gitignore rename to packages/npm-bcrypt/.gitignore diff --git a/packages/non-core/npm-bcrypt/.npm/package/.gitignore b/packages/npm-bcrypt/.npm/package/.gitignore similarity index 100% rename from packages/non-core/npm-bcrypt/.npm/package/.gitignore rename to packages/npm-bcrypt/.npm/package/.gitignore diff --git a/packages/non-core/npm-bcrypt/.npm/package/README b/packages/npm-bcrypt/.npm/package/README similarity index 100% rename from packages/non-core/npm-bcrypt/.npm/package/README rename to packages/npm-bcrypt/.npm/package/README diff --git a/packages/npm-bcrypt/.npm/package/npm-shrinkwrap.json b/packages/npm-bcrypt/.npm/package/npm-shrinkwrap.json new file mode 100644 index 0000000000..95b0f873f6 --- /dev/null +++ b/packages/npm-bcrypt/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "bcryptjs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.3.0.tgz", + "from": "bcryptjs@2.3.0" + } + } +} diff --git a/packages/npm-bcrypt/.versions b/packages/npm-bcrypt/.versions new file mode 100644 index 0000000000..fe86c99b06 --- /dev/null +++ b/packages/npm-bcrypt/.versions @@ -0,0 +1,5 @@ +meteor@1.2.16 +modules@0.7.5 +modules-runtime@0.7.5 +npm-bcrypt@0.9.0 +underscore@1.0.9 diff --git a/packages/npm-bcrypt/package.js b/packages/npm-bcrypt/package.js new file mode 100644 index 0000000000..61f5431c66 --- /dev/null +++ b/packages/npm-bcrypt/package.js @@ -0,0 +1,15 @@ +Package.describe({ + summary: "Wrapper around the bcrypt npm package", + version: "0.9.0", + documentation: null +}); + +Npm.depends({ + bcryptjs: "2.3.0" +}); + +Package.onUse(function (api) { + api.use("modules@0.7.5", "server"); + api.mainModule("wrapper.js", "server"); + api.export("NpmModuleBcrypt", "server"); +}); diff --git a/packages/npm-bcrypt/wrapper.js b/packages/npm-bcrypt/wrapper.js new file mode 100644 index 0000000000..eac4ad51f0 --- /dev/null +++ b/packages/npm-bcrypt/wrapper.js @@ -0,0 +1,38 @@ +var assert = require("assert"); + +// The bcryptjs package has a slightly larger API than the native bcrypt +// package, so we stick to the smaller API for consistency. +var methods = { + compare: true, + compareSync: true, + genSalt: true, + genSaltSync: true, + getRounds: true, + hash: true, + hashSync: true +}; + +try { + // If you really need the native `bcrypt` package, then you should + // `meteor npm install --save bcrypt` into the node_modules directory in + // the root of your application. + var bcrypt = require("bcrypt"); +} catch (e) { + bcrypt = require("bcryptjs"); + console.warn([ + "Note: you are using a pure-JavaScript implementation of bcrypt.", + "While this implementation will work correctly, it is known to be", + "approximately three times slower than the native implementation.", + "In order to use the native implementation instead, run", + "", + " meteor npm install --save bcrypt", + "", + "in the root directory of your application." + ].join("\n")); +} + +exports.NpmModuleBcrypt = {}; +Object.keys(methods).forEach(function (key) { + assert.strictEqual(typeof bcrypt[key], "function"); + exports.NpmModuleBcrypt[key] = bcrypt[key]; +}); diff --git a/tools/tests/package-tests.js b/tools/tests/package-tests.js index 7c9151a51a..d2ca44c5ba 100644 --- a/tools/tests/package-tests.js +++ b/tools/tests/package-tests.js @@ -424,14 +424,6 @@ selftest.define("show unknown version of package", function () { run.waitSecs(5); run.matchErr("meteor-base@0.123.456: not found"); run.expectExit(1); - - // This package exists in the server (we need it to publish the tool), but is - // not a local package. - run = s.run("show", "npm-bcrypt@local"); - run.waitSecs(5); - run.matchErr("npm-bcrypt@local: not found"); - run.expectExit(1); - }); selftest.define("circular dependency errors", function () { From e4e87ecce43d13ae1ccfcbd1bcbda2cf76589a9e Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 10 Aug 2016 16:53:56 -0400 Subject: [PATCH 075/688] Don't touch ~/.meteor/meteor after background updates. (#7616) --- tools/packaging/updater.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/packaging/updater.js b/tools/packaging/updater.js index d8e1eb38a5..07bfaecb66 100644 --- a/tools/packaging/updater.js +++ b/tools/packaging/updater.js @@ -61,8 +61,6 @@ var checkForUpdate = function (showBanner, printErrors) { return; } - updateMeteorToolSymlink(printErrors); - maybeShowBanners(); }; From fe9f46c8a01bb503b6cad3bb54464639fb2d84c8 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 10 Aug 2016 17:38:59 -0400 Subject: [PATCH 076/688] Upgrade ecmascript-runtime to include stage 4 proposals. https://github.com/meteor/ecmascript-runtime/pull/4 --- packages/ecmascript-runtime/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index 747da9d95b..0174dcc23a 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,13 +1,13 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.13", + version: "0.3.14", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" }); Npm.depends({ - "meteor-ecmascript-runtime": "0.2.8", + "meteor-ecmascript-runtime": "0.2.9", }); Package.onUse(function(api) { From 491a413cb5f81583c36d4805e5e65695a54becf6 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 10 Aug 2016 19:05:21 -0400 Subject: [PATCH 077/688] Update shrinkwrap for ecmascript-runtime. --- .../.npm/package/npm-shrinkwrap.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json b/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json index 3a25c59713..2d4e33d663 100644 --- a/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json +++ b/packages/ecmascript-runtime/.npm/package/npm-shrinkwrap.json @@ -1,14 +1,14 @@ { "dependencies": { "core-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.1.tgz", - "from": "core-js@1.2.1" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "from": "core-js@2.4.1" }, "meteor-ecmascript-runtime": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/meteor-ecmascript-runtime/-/meteor-ecmascript-runtime-0.2.8.tgz", - "from": "meteor-ecmascript-runtime@0.2.8" + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/meteor-ecmascript-runtime/-/meteor-ecmascript-runtime-0.2.9.tgz", + "from": "meteor-ecmascript-runtime@0.2.9" } } } From e91b342360426b24da6f5d5dd39054517d1e68ac Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Thu, 11 Aug 2016 07:10:30 +0800 Subject: [PATCH 078/688] Update README.md for Windows users. (#7610) * Update README.md * Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f27f3c1ff5..a34d26f161 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ Next, read the [guide](http://guide.meteor.com) or the reference documentation a ## Quick Start -Install Meteor: +On Windows, simply go to https://www.meteor.com/install and use the Windows installer. + +On Linux/macOS, use this line: ```bash curl https://install.meteor.com/ | sh @@ -91,6 +93,8 @@ rm -rf ~/.meteor/ sudo rm /usr/local/bin/meteor ``` +On Windows, just run the uninstaller from your Control Panel. + ## Developer Resources Building an application with Meteor? From 3c7f83778f31ae1d3eed6e71bf1675662b99648c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 09:11:40 -0400 Subject: [PATCH 079/688] Move server-side component of `meteor shell` into a package. (#7624) This will make it much easier to fix bugs and make improvements going forward, since they won't have to wait for the next release of Meteor. One functional change: when the parent process exits, it no longer forces all connected shell clients to disconnect, which is actually a more convenient behavior, because it gives the clients a chance to reconnect when/if the server starts up again, and it's easy enough to kill the clients if that's what you want. --- packages/shell-server/README.md | 4 + packages/shell-server/main.js | 7 + packages/shell-server/package.js | 11 + packages/shell-server/shell-server.js | 501 +++++++++++++++++++++ tools/isobuild/bundler.js | 1 - tools/runners/run-app.js | 9 - tools/shell-client.js | 11 +- tools/static-assets/server/boot.js | 5 - tools/static-assets/server/shell-server.js | 499 -------------------- tools/static-assets/skel/.meteor/packages | 1 + tools/tests/apps/shell/.meteor/packages | 1 + tools/tests/apps/shell/.meteor/versions | 9 +- tools/tool-testing/selftest.js | 3 +- tools/upgraders.js | 6 + 14 files changed, 546 insertions(+), 522 deletions(-) create mode 100644 packages/shell-server/README.md create mode 100644 packages/shell-server/main.js create mode 100644 packages/shell-server/package.js create mode 100644 packages/shell-server/shell-server.js delete mode 100644 tools/static-assets/server/shell-server.js diff --git a/packages/shell-server/README.md b/packages/shell-server/README.md new file mode 100644 index 0000000000..be30895185 --- /dev/null +++ b/packages/shell-server/README.md @@ -0,0 +1,4 @@ +# `meteor shell` + +This code used to be integrated into the Meteor command-line tool, which +made it difficult to release frequent updates. diff --git a/packages/shell-server/main.js b/packages/shell-server/main.js new file mode 100644 index 0000000000..ab044b88b4 --- /dev/null +++ b/packages/shell-server/main.js @@ -0,0 +1,7 @@ +export * from "./shell-server.js"; +import { listen } from "./shell-server.js"; + +const shellDir = process.env.METEOR_SHELL_DIR; +if (shellDir) { + listen(shellDir); +} diff --git a/packages/shell-server/package.js b/packages/shell-server/package.js new file mode 100644 index 0000000000..689b52f701 --- /dev/null +++ b/packages/shell-server/package.js @@ -0,0 +1,11 @@ +Package.describe({ + name: "shell-server", + version: "0.2.1", + summary: "Server-side component of the `meteor shell` command.", + documentation: "README.md" +}); + +Package.onUse(function(api) { + api.use("ecmascript@0.5.7", "server"); + api.mainModule("main.js", "server"); +}); diff --git a/packages/shell-server/shell-server.js b/packages/shell-server/shell-server.js new file mode 100644 index 0000000000..eff77e0468 --- /dev/null +++ b/packages/shell-server/shell-server.js @@ -0,0 +1,501 @@ +var assert = require("assert"); +var path = require("path"); +var stream = require("stream"); +var fs = require("fs"); +var net = require("net"); +var tty = require("tty"); +var vm = require("vm"); +var _ = require("underscore"); +var INFO_FILE_MODE = parseInt("600", 8); // Only the owner can read or write. +var EXITING_MESSAGE = "Shell exiting..."; + +// Invoked by the server process to listen for incoming connections from +// shell clients. Each connection gets its own REPL instance. +export function listen(shellDir) { + function callback() { + new Server(shellDir).listen(); + } + + // If the server is still in the very early stages of starting up, + // Meteor.startup may not available yet. + if (typeof Meteor === "object") { + Meteor.startup(callback); + } else if (typeof __meteor_bootstrap__ === "object") { + var hooks = __meteor_bootstrap__.startupHooks; + if (hooks) { + hooks.push(callback); + } else { + // As a fallback, just call the callback asynchronously. + setImmediate(callback); + } + } +} + +// Disabling the shell causes all attached clients to disconnect and exit. +export function disable(shellDir) { + try { + // Replace info.json with a file that says the shell server is + // disabled, so that any connected shell clients will fail to + // reconnect after the server process closes their sockets. + fs.writeFileSync( + getInfoFile(shellDir), + JSON.stringify({ + status: "disabled", + reason: "Shell server has shut down." + }) + "\n", + { mode: INFO_FILE_MODE } + ); + } catch (ignored) {} +} + +class Server { + constructor(shellDir) { + var self = this; + assert.ok(self instanceof Server); + + self.shellDir = shellDir; + self.key = Math.random().toString(36).slice(2); + + self.server = net.createServer(function(socket) { + self.onConnection(socket); + }).on("error", function(err) { + console.error(err.stack); + }); + } + + listen() { + var self = this; + var infoFile = getInfoFile(self.shellDir); + + fs.unlink(infoFile, function() { + self.server.listen(0, "127.0.0.1", function() { + fs.writeFileSync(infoFile, JSON.stringify({ + status: "enabled", + port: self.server.address().port, + key: self.key + }) + "\n", { + mode: INFO_FILE_MODE + }); + }); + }); + } + + onConnection(socket) { + var self = this; + + // Make sure this function doesn't try to write anything to the socket + // after it has been closed. + socket.on("close", function() { + socket = null; + }); + + // If communication is not established within 1000ms of the first + // connection, forcibly close the socket. + var timeout = setTimeout(function() { + if (socket) { + socket.removeAllListeners("data"); + socket.end(EXITING_MESSAGE + "\n"); + } + }, 1000); + + // Let connecting clients configure certain REPL options by sending a + // JSON object over the socket. For example, only the client knows + // whether it's running a TTY or an Emacs subshell or some other kind of + // terminal, so the client must decide the value of options.terminal. + readJSONFromStream(socket, function (error, options, replInputSocket) { + clearTimeout(timeout); + + if (error) { + socket = null; + console.error(error.stack); + return; + } + + if (options.key !== self.key) { + if (socket) { + socket.end(EXITING_MESSAGE + "\n"); + } + return; + } + delete options.key; + + if (options.evaluateAndExit) { + evalCommand.call( + Object.create(null), // Dummy repl object without ._RecoverableError. + "(" + options.evaluateAndExit.command + ")", + null, // evalCommand ignores the context parameter, anyway + options.evaluateAndExit.filename || "", + function (error, result) { + if (socket) { + var message = error ? { + error: error + "", + code: 1 + } : { + result: result + }; + + // Sending back a JSON payload allows the client to + // distinguish between errors and successful results. + socket.end(JSON.stringify(message) + "\n"); + } + } + ); + return; + } + delete options.evaluateAndExit; + + // Immutable options. + _.extend(options, { + input: replInputSocket, + output: socket + }); + + // Overridable options. + _.defaults(options, { + prompt: "> ", + terminal: true, + useColors: true, + useGlobal: true, + ignoreUndefined: true, + }); + + self.startREPL(options); + }); + } + + startREPL(options) { + var self = this; + + if (! options.output.columns) { + // The REPL's tab completion logic assumes process.stdout is a TTY, + // and while that isn't technically true here, we can get tab + // completion to behave correctly if we fake the .columns property. + options.output.columns = getTerminalWidth(); + } + + // Make sure this function doesn't try to write anything to the output + // stream after it has been closed. + options.output.on("close", function() { + options.output = null; + }); + + var repl = self.repl = require("repl").start(options); + + // History persists across shell sessions! + self.initializeHistory(); + + // Save the global `_` object in the server. This is probably defined by the + // underscore package. It is unlikely to be the same object as the `var _ = + // require('underscore')` in this file! + var originalUnderscore = repl.context._; + + Object.defineProperty(repl.context, "_", { + // Force the global _ variable to remain bound to underscore. + get: function () { return originalUnderscore; }, + + // Expose the last REPL result as __ instead of _. + set: function(lastResult) { + repl.context.__ = lastResult; + }, + + enumerable: true, + + // Allow this property to be (re)defined more than once (e.g. each + // time the server restarts). + configurable: true + }); + + if (Package.modules) { + // Use the same `require` function and `module` object visible to the + // application. + var toBeInstalled = {}; + var shellModuleName = "meteor-shell-" + + Math.random().toString(36).slice(2) + ".js"; + + toBeInstalled[shellModuleName] = function (require, exports, module) { + repl.context.module = module; + repl.context.require = require; + + // Tab completion sometimes uses require.extensions, but only for + // the keys. + require.extensions = { + ".js": true, + ".json": true, + ".node": true, + }; + }; + + // This populates repl.context.{module,require} by evaluating the + // module defined above. + Package.modules.meteorInstall(toBeInstalled)("./" + shellModuleName); + } + + repl.context.repl = repl; + + // Some improvements to the existing help messages. + function addHelp(cmd, helpText) { + var info = repl.commands[cmd] || repl.commands["." + cmd]; + if (info) { + info.help = helpText; + } + } + addHelp("break", "Terminate current command input and display new prompt"); + addHelp("exit", "Disconnect from server and leave shell"); + addHelp("help", "Show this help information"); + + // When the REPL exits, signal the attached client to exit by sending it + // the special EXITING_MESSAGE. + repl.on("exit", function() { + if (options.output) { + options.output.write(EXITING_MESSAGE + "\n"); + options.output.end(); + } + }); + + // When the server process exits, end the output stream but do not + // signal the attached client to exit. + process.on("exit", function() { + if (options.output) { + options.output.end(); + } + }); + + // This Meteor-specific shell command rebuilds the application as if a + // change was made to server code. + repl.defineCommand("reload", { + help: "Restart the server and the shell", + action: function() { + process.exit(0); + } + }); + + // Trigger one recoverable error using the default eval function, just + // to capture the Recoverable error constructor, so that our custom + // evalCommand function can wrap recoverable errors properly. + repl.eval( + "{", null, "", + function (error) { + // Capture the Recoverable error constructor. + repl._RecoverableError = error && error.constructor; + + // Now set repl.eval to the actual evalCommand function that we want + // to use, bound to repl._domain if necessary. + repl.eval = repl._domain + ? repl._domain.bind(evalCommand) + : evalCommand; + + // Terminate the partial evaluation of the { command. + repl.commands["break"].action.call(repl); + } + ); + } + + // This function allows a persistent history of shell commands to be saved + // to and loaded from .meteor/local/shell-history. + initializeHistory() { + var self = this; + var rli = self.repl.rli; + var historyFile = getHistoryFile(self.shellDir); + var historyFd = fs.openSync(historyFile, "a+"); + var historyLines = fs.readFileSync(historyFile, "utf8").split("\n"); + var seenLines = Object.create(null); + + if (! rli.history) { + rli.history = []; + rli.historyIndex = -1; + } + + while (rli.history && historyLines.length > 0) { + var line = historyLines.pop(); + if (line && /\S/.test(line) && ! seenLines[line]) { + rli.history.push(line); + seenLines[line] = true; + } + } + + rli.addListener("line", function(line) { + if (historyFd >= 0 && /\S/.test(line)) { + fs.writeSync(historyFd, line + "\n"); + } + }); + + self.repl.on("exit", function() { + fs.closeSync(historyFd); + historyFd = -1; + }); + } +} + +function readJSONFromStream(inputStream, callback) { + var outputStream = new stream.PassThrough; + var dataSoFar = ""; + + function onData(buffer) { + var lines = buffer.toString("utf8").split("\n"); + + while (lines.length > 0) { + dataSoFar += lines.shift(); + + try { + var json = JSON.parse(dataSoFar); + } catch (error) { + if (error instanceof SyntaxError) { + continue; + } + + return finish(error); + } + + if (lines.length > 0) { + outputStream.write(lines.join("\n")); + } + + inputStream.pipe(outputStream); + + return finish(null, json); + } + } + + function onClose() { + finish(new Error("stream unexpectedly closed")); + } + + var finished = false; + function finish(error, json) { + if (! finished) { + finished = true; + inputStream.removeListener("data", onData); + inputStream.removeListener("error", finish); + inputStream.removeListener("close", onClose); + callback(error, json, outputStream); + } + } + + inputStream.on("data", onData); + inputStream.on("error", finish); + inputStream.on("close", onClose); +} + +function getInfoFile(shellDir) { + return path.join(shellDir, "info.json"); +} + +function getHistoryFile(shellDir) { + return path.join(shellDir, "history"); +} + +function getTerminalWidth() { + try { + // Inspired by https://github.com/TooTallNate/ttys/blob/master/index.js + var fd = fs.openSync("/dev/tty", "r"); + assert.ok(tty.isatty(fd)); + var ws = new tty.WriteStream(fd); + ws.end(); + return ws.columns; + } catch (fancyApproachWasTooFancy) { + return 80; + } +} + +// Shell commands need to be executed in a Fiber in case they call into +// code that yields. Using a Promise is an even better idea, since it runs +// its callbacks in Fibers drawn from a pool, so the Fibers are recycled. +var evalCommandPromise = Promise.resolve(); + +function evalCommand(command, context, filename, callback) { + var repl = this; + + function finish(error, result) { + if (error) { + if (repl._RecoverableError && + isRecoverableError(error, repl)) { + callback(new repl._RecoverableError(error)); + } else { + callback(error); + } + } else { + callback(null, result); + } + } + + if (Package.ecmascript) { + var noParens = stripParens(command); + if (noParens !== command) { + var classMatch = /^\s*class\s+(\w+)/.exec(noParens); + if (classMatch && classMatch[1] !== "extends") { + // If the command looks like a named ES2015 class, we remove the + // extra layer of parentheses added by the REPL so that the + // command will be evaluated as a class declaration rather than as + // a named class expression. Note that you can still type (class A + // {}) explicitly to evaluate a named class expression. The REPL + // code that calls evalCommand handles named function expressions + // similarly (first with and then without parentheses), but that + // code doesn't know about ES2015 classes, which is why we have to + // handle them here. + command = noParens; + } + } + + try { + command = Package.ecmascript.ECMAScript.compileForShell(command); + } catch (error) { + finish(error); + return; + } + } + + try { + var script = new vm.Script(command, { + filename: filename, + displayErrors: false + }); + } catch (parseError) { + finish(parseError); + return; + } + + evalCommandPromise.then(function () { + finish(null, script.runInThisContext()); + }).catch(finish); +} + +function stripParens(command) { + if (command.charAt(0) === "(" && + command.charAt(command.length - 1) === ")") { + return command.slice(1, command.length - 1); + } + return command; +} + +// The bailOnIllegalToken and isRecoverableError functions are taken from +// https://github.com/nodejs/node/blob/c9e670ea2a/lib/repl.js#L1227-L1253 +function bailOnIllegalToken(parser) { + return parser._literal === null && + ! parser.blockComment && + ! parser.regExpLiteral; +} + +// If the error is that we've unexpectedly ended the input, +// then let the user try to recover by adding more input. +function isRecoverableError(e, repl) { + if (e && e.name === 'SyntaxError') { + var message = e.message; + if (message === 'Unterminated template literal' || + message === 'Missing } in template expression') { + repl._inTemplateLiteral = true; + return true; + } + + if (message.startsWith('Unexpected end of input') || + message.startsWith('missing ) after argument list') || + message.startsWith('Unexpected token')) { + return true; + } + + if (message === 'Invalid or unexpected token') { + return ! bailOnIllegalToken(repl.lineParser); + } + } + + return false; +} diff --git a/tools/isobuild/bundler.js b/tools/isobuild/bundler.js index 8a342eb9da..eb8b9dabd6 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -2180,7 +2180,6 @@ class ServerTarget extends JsImageTarget { _.each([ "boot.js", "boot-utils.js", - "shell-server.js", "server-json.js", "mini-files.js", "npm-require.js", diff --git a/tools/runners/run-app.js b/tools/runners/run-app.js index 1b7432d665..8a5fa568eb 100644 --- a/tools/runners/run-app.js +++ b/tools/runners/run-app.js @@ -138,15 +138,6 @@ _.extend(AppProcess.prototype, { // exception and the whole app dies. // http://stackoverflow.com/questions/2893458/uncatchable-errors-in-node-js self.proc.stdin.on('error', function () {}); - - // When the parent process exits (i.e. the server is shutting down and - // not merely restarting), make sure to disconnect any still-connected - // shell clients. - require('../tool-env/cleanup.js').onExit(function() { - require('../static-assets/server/shell-server.js').disable( - self.projectContext.getMeteorShellDirectory() - ); - }); }, _maybeCallOnExit: function (code, signal) { diff --git a/tools/shell-client.js b/tools/shell-client.js index 35071377b5..4f6bc936ee 100644 --- a/tools/shell-client.js +++ b/tools/shell-client.js @@ -1,12 +1,17 @@ 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; -var server = require('./static-assets/server/shell-server.js'); -var EXITING_MESSAGE = server.EXITING_MESSAGE; -var getInfoFile = server.getInfoFile; + +// These two values (EXITING_MESSAGE and getInfoFile) must match the +// values used by the shell-server package. +var EXITING_MESSAGE = "Shell exiting..."; +function getInfoFile(shellDir) { + return path.join(shellDir, "info.json"); +} // Invoked by the process running `meteor shell` to attempt to connect to // the server via the socket file. diff --git a/tools/static-assets/server/boot.js b/tools/static-assets/server/boot.js index e20594fde9..5dd474e375 100644 --- a/tools/static-assets/server/boot.js +++ b/tools/static-assets/server/boot.js @@ -96,11 +96,6 @@ sourcemap_support.install({ wrapCallSite: wrapCallSite }); -// Only enabled by default in development. -if (process.env.METEOR_SHELL_DIR) { - require('./shell-server.js').listen(process.env.METEOR_SHELL_DIR); -} - // As a replacement to the old keepalives mechanism, check for a running // parent every few seconds. Exit if the parent is not running. // diff --git a/tools/static-assets/server/shell-server.js b/tools/static-assets/server/shell-server.js deleted file mode 100644 index 3f2c0e63be..0000000000 --- a/tools/static-assets/server/shell-server.js +++ /dev/null @@ -1,499 +0,0 @@ -var assert = require("assert"); -var path = require("path"); -var stream = require("stream"); -var fs = require("fs"); -var net = require("net"); -var tty = require("tty"); -var vm = require("vm"); -var _ = require("underscore"); -var INFO_FILE_MODE = parseInt("600", 8); // Only the owner can read or write. -var EXITING_MESSAGE = - // Exported so that ./client.js can know what to expect. - exports.EXITING_MESSAGE = "Shell exiting..."; - -var Promise = require("promise/lib/es6-extensions"); -require("meteor-promise").makeCompatible(Promise, require("fibers")); - -// Invoked by the server process to listen for incoming connections from -// shell clients. Each connection gets its own REPL instance. -exports.listen = function listen(shellDir) { - function callback() { - new Server(shellDir).listen(); - } - - // If the server is still in the very early stages of starting up, - // Meteor.startup may not available yet. - if (typeof Meteor === "object") { - Meteor.startup(callback); - } else if (typeof __meteor_bootstrap__ === "object") { - var hooks = __meteor_bootstrap__.startupHooks; - if (hooks) { - hooks.push(callback); - } else { - // As a fallback, just call the callback asynchronously. - setImmediate(callback); - } - } -}; - -// Disabling the shell causes all attached clients to disconnect and exit. -exports.disable = function disable(shellDir) { - try { - // Replace info.json with a file that says the shell server is - // disabled, so that any connected shell clients will fail to - // reconnect after the server process closes their sockets. - fs.writeFileSync( - getInfoFile(shellDir), - JSON.stringify({ - status: "disabled", - reason: "Shell server has shut down." - }) + "\n", - { mode: INFO_FILE_MODE } - ); - } catch (ignored) {} -}; - -function Server(shellDir) { - var self = this; - assert.ok(self instanceof Server); - - self.shellDir = shellDir; - self.key = Math.random().toString(36).slice(2); - - self.server = net.createServer(function(socket) { - self.onConnection(socket); - }).on("error", function(err) { - console.error(err.stack); - }); -} - -var Sp = Server.prototype; - -Sp.listen = function listen() { - var self = this; - var infoFile = getInfoFile(self.shellDir); - - fs.unlink(infoFile, function() { - self.server.listen(0, "127.0.0.1", function() { - fs.writeFileSync(infoFile, JSON.stringify({ - status: "enabled", - port: self.server.address().port, - key: self.key - }) + "\n", { - mode: INFO_FILE_MODE - }); - }); - }); -}; - -function readJSONFromStream(inputStream, callback) { - var outputStream = new stream.PassThrough; - var dataSoFar = ""; - - function onData(buffer) { - var lines = buffer.toString("utf8").split("\n"); - - while (lines.length > 0) { - dataSoFar += lines.shift(); - - try { - var json = JSON.parse(dataSoFar); - } catch (error) { - if (error instanceof SyntaxError) { - continue; - } - - return finish(error); - } - - if (lines.length > 0) { - outputStream.write(lines.join("\n")); - } - - inputStream.pipe(outputStream); - - return finish(null, json); - } - } - - function onClose() { - finish(new Error("stream unexpectedly closed")); - } - - var finished = false; - function finish(error, json) { - if (! finished) { - finished = true; - inputStream.removeListener("data", onData); - inputStream.removeListener("error", finish); - inputStream.removeListener("close", onClose); - callback(error, json, outputStream); - } - } - - inputStream.on("data", onData); - inputStream.on("error", finish); - inputStream.on("close", onClose); -} - -Sp.onConnection = function onConnection(socket) { - var self = this; - - // Make sure this function doesn't try to write anything to the socket - // after it has been closed. - socket.on("close", function() { - socket = null; - }); - - // If communication is not established within 1000ms of the first - // connection, forcibly close the socket. - var timeout = setTimeout(function() { - if (socket) { - socket.removeAllListeners("data"); - socket.end(EXITING_MESSAGE + "\n"); - } - }, 1000); - - // Let connecting clients configure certain REPL options by sending a - // JSON object over the socket. For example, only the client knows - // whether it's running a TTY or an Emacs subshell or some other kind of - // terminal, so the client must decide the value of options.terminal. - readJSONFromStream(socket, function (error, options, replInputSocket) { - clearTimeout(timeout); - - if (error) { - socket = null; - console.error(error.stack); - return; - } - - if (options.key !== self.key) { - if (socket) { - socket.end(EXITING_MESSAGE + "\n"); - } - return; - } - delete options.key; - - if (options.evaluateAndExit) { - evalCommand.call( - Object.create(null), // Dummy repl object without ._RecoverableError. - "(" + options.evaluateAndExit.command + ")", - null, // evalCommand ignores the context parameter, anyway - options.evaluateAndExit.filename || "", - function (error, result) { - if (socket) { - var message = error ? { - error: error + "", - code: 1 - } : { - result: result - }; - - // Sending back a JSON payload allows the client to - // distinguish between errors and successful results. - socket.end(JSON.stringify(message) + "\n"); - } - } - ); - return; - } - delete options.evaluateAndExit; - - // Immutable options. - _.extend(options, { - input: replInputSocket, - output: socket - }); - - // Overridable options. - _.defaults(options, { - prompt: "> ", - terminal: true, - useColors: true, - useGlobal: true, - ignoreUndefined: true, - }); - - self.startREPL(options); - }); -}; - -Sp.startREPL = function startREPL(options) { - var self = this; - - if (! options.output.columns) { - // The REPL's tab completion logic assumes process.stdout is a TTY, - // and while that isn't technically true here, we can get tab - // completion to behave correctly if we fake the .columns property. - options.output.columns = getTerminalWidth(); - } - - // Make sure this function doesn't try to write anything to the output - // stream after it has been closed. - options.output.on("close", function() { - options.output = null; - }); - - var repl = self.repl = require("repl").start(options); - - // History persists across shell sessions! - self.initializeHistory(); - - // Save the global `_` object in the server. This is probably defined by the - // underscore package. It is unlikely to be the same object as the `var _ = - // require('underscore')` in this file! - var originalUnderscore = repl.context._; - - Object.defineProperty(repl.context, "_", { - // Force the global _ variable to remain bound to underscore. - get: function () { return originalUnderscore; }, - - // Expose the last REPL result as __ instead of _. - set: function(lastResult) { - repl.context.__ = lastResult; - }, - - enumerable: true, - - // Allow this property to be (re)defined more than once (e.g. each - // time the server restarts). - configurable: true - }); - - if (Package.modules) { - // Use the same `require` function and `module` object visible to the - // application. - var toBeInstalled = {}; - var shellModuleName = "meteor-shell-" + - Math.random().toString(36).slice(2) + ".js"; - - toBeInstalled[shellModuleName] = function (require, exports, module) { - repl.context.module = module; - repl.context.require = require; - }; - - // This populates repl.context.{module,require} by evaluating the - // module defined above. - Package.modules.meteorInstall(toBeInstalled)("./" + shellModuleName); - } - - repl.context.repl = repl; - - // Some improvements to the existing help messages. - function addHelp(cmd, helpText) { - var info = repl.commands[cmd] || repl.commands["." + cmd]; - if (info) { - info.help = helpText; - } - } - addHelp("break", "Terminate current command input and display new prompt"); - addHelp("exit", "Disconnect from server and leave shell"); - addHelp("help", "Show this help information"); - - // When the REPL exits, signal the attached client to exit by sending it - // the special EXITING_MESSAGE. - repl.on("exit", function() { - if (options.output) { - options.output.write(EXITING_MESSAGE + "\n"); - options.output.end(); - } - }); - - // When the server process exits, end the output stream but do not - // signal the attached client to exit. - process.on("exit", function() { - if (options.output) { - options.output.end(); - } - }); - - // This Meteor-specific shell command rebuilds the application as if a - // change was made to server code. - repl.defineCommand("reload", { - help: "Restart the server and the shell", - action: function() { - process.exit(0); - } - }); - - // Trigger one recoverable error using the default eval function, just - // to capture the Recoverable error constructor, so that our custom - // evalCommand function can wrap recoverable errors properly. - repl.eval( - "{", null, "", - function (error) { - // Capture the Recoverable error constructor. - repl._RecoverableError = error && error.constructor; - - // Now set repl.eval to the actual evalCommand function that we want - // to use, bound to repl._domain if necessary. - repl.eval = repl._domain - ? repl._domain.bind(evalCommand) - : evalCommand; - - // Terminate the partial evaluation of the { command. - repl.commands["break"].action.call(repl); - } - ); -}; - -function getInfoFile(shellDir) { - return path.join(shellDir, "info.json"); -} -exports.getInfoFile = getInfoFile; - -function getHistoryFile(shellDir) { - return path.join(shellDir, "history"); -} - -function getTerminalWidth() { - try { - // Inspired by https://github.com/TooTallNate/ttys/blob/master/index.js - var fd = fs.openSync("/dev/tty", "r"); - assert.ok(tty.isatty(fd)); - var ws = new tty.WriteStream(fd); - ws.end(); - return ws.columns; - } catch (fancyApproachWasTooFancy) { - return 80; - } -} - -// Shell commands need to be executed in a Fiber in case they call into -// code that yields. Using a Promise is an even better idea, since it runs -// its callbacks in Fibers drawn from a pool, so the Fibers are recycled. -var evalCommandPromise = Promise.resolve(); - -function evalCommand(command, context, filename, callback) { - var repl = this; - - function finish(error, result) { - if (error) { - if (repl._RecoverableError && - isRecoverableError(error, repl)) { - callback(new repl._RecoverableError(error)); - } else { - callback(error); - } - } else { - callback(null, result); - } - } - - if (Package.ecmascript) { - var noParens = stripParens(command); - if (noParens !== command) { - var classMatch = /^\s*class\s+(\w+)/.exec(noParens); - if (classMatch && classMatch[1] !== "extends") { - // If the command looks like a named ES2015 class, we remove the - // extra layer of parentheses added by the REPL so that the - // command will be evaluated as a class declaration rather than as - // a named class expression. Note that you can still type (class A - // {}) explicitly to evaluate a named class expression. The REPL - // code that calls evalCommand handles named function expressions - // similarly (first with and then without parentheses), but that - // code doesn't know about ES2015 classes, which is why we have to - // handle them here. - command = noParens; - } - } - - try { - command = Package.ecmascript.ECMAScript.compileForShell(command); - } catch (error) { - finish(error); - return; - } - } - - try { - var script = new vm.Script(command, { - filename: filename, - displayErrors: false - }); - } catch (parseError) { - finish(parseError); - return; - } - - evalCommandPromise.then(function () { - finish(null, script.runInThisContext()); - }).catch(finish); -} - -function stripParens(command) { - if (command.charAt(0) === "(" && - command.charAt(command.length - 1) === ")") { - return command.slice(1, command.length - 1); - } - return command; -} - -// The bailOnIllegalToken and isRecoverableError functions are taken from -// https://github.com/nodejs/node/blob/c9e670ea2a/lib/repl.js#L1227-L1253 -function bailOnIllegalToken(parser) { - return parser._literal === null && - ! parser.blockComment && - ! parser.regExpLiteral; -} - -// If the error is that we've unexpectedly ended the input, -// then let the user try to recover by adding more input. -function isRecoverableError(e, repl) { - if (e && e.name === 'SyntaxError') { - var message = e.message; - if (message === 'Unterminated template literal' || - message === 'Missing } in template expression') { - repl._inTemplateLiteral = true; - return true; - } - - if (message.startsWith('Unexpected end of input') || - message.startsWith('missing ) after argument list') || - message.startsWith('Unexpected token')) { - return true; - } - - if (message === 'Invalid or unexpected token') { - return ! bailOnIllegalToken(repl.lineParser); - } - } - - return false; -} - -// This function allows a persistent history of shell commands to be saved -// to and loaded from .meteor/local/shell-history. -Sp.initializeHistory = function initializeHistory() { - var self = this; - var rli = self.repl.rli; - var historyFile = getHistoryFile(self.shellDir); - var historyFd = fs.openSync(historyFile, "a+"); - var historyLines = fs.readFileSync(historyFile, "utf8").split("\n"); - var seenLines = Object.create(null); - - if (! rli.history) { - rli.history = []; - rli.historyIndex = -1; - } - - while (rli.history && historyLines.length > 0) { - var line = historyLines.pop(); - if (line && /\S/.test(line) && ! seenLines[line]) { - rli.history.push(line); - seenLines[line] = true; - } - } - - rli.addListener("line", function(line) { - if (historyFd >= 0 && /\S/.test(line)) { - fs.writeSync(historyFd, line + "\n"); - } - }); - - self.repl.on("exit", function() { - fs.closeSync(historyFd); - historyFd = -1; - }); -}; diff --git a/tools/static-assets/skel/.meteor/packages b/tools/static-assets/skel/.meteor/packages index d4c8001f20..1615051104 100644 --- a/tools/static-assets/skel/.meteor/packages +++ b/tools/static-assets/skel/.meteor/packages @@ -16,6 +16,7 @@ standard-minifier-css # CSS minifier run for production mode standard-minifier-js # JS minifier run for production mode es5-shim # ECMAScript 5 compatibility for older browsers. ecmascript # Enable ECMAScript2015+ syntax in app code +shell-server # Server-side component of the `meteor shell` command autopublish # Publish all data to the clients (for prototyping) insecure # Allow all DB writes from clients (for prototyping) diff --git a/tools/tests/apps/shell/.meteor/packages b/tools/tests/apps/shell/.meteor/packages index d4c8001f20..c45a0da55a 100644 --- a/tools/tests/apps/shell/.meteor/packages +++ b/tools/tests/apps/shell/.meteor/packages @@ -19,3 +19,4 @@ ecmascript # Enable ECMAScript2015+ syntax in app code autopublish # Publish all data to the clients (for prototyping) insecure # Allow all DB writes from clients (for prototyping) +shell-server diff --git a/tools/tests/apps/shell/.meteor/versions b/tools/tests/apps/shell/.meteor/versions index 40d32caaa2..80b62f9734 100644 --- a/tools/tests/apps/shell/.meteor/versions +++ b/tools/tests/apps/shell/.meteor/versions @@ -20,7 +20,7 @@ ddp-server@1.3.9 deps@1.0.12 diff-sequence@1.0.6 ecmascript@0.5.7 -ecmascript-runtime@0.3.12 +ecmascript-runtime@0.3.14 ejson@1.0.12 es5-shim@4.6.13 fastclick@1.0.12 @@ -38,7 +38,7 @@ logging@1.1.14 meteor@1.2.16 meteor-base@1.0.4 minifier-css@1.2.13 -minifier-js@1.2.13 +minifier-js@1.2.14 minimongo@1.0.17 mobile-experience@1.0.4 mobile-status-bar@1.0.12 @@ -55,10 +55,11 @@ reactive-var@1.0.10 reload@1.1.10 retry@1.0.8 routepolicy@1.0.11 +shell-server@0.2.1 spacebars@1.0.12 spacebars-compiler@1.0.12 -standard-minifier-css@1.1.8 -standard-minifier-js@1.1.8 +standard-minifier-css@1.2.0 +standard-minifier-js@1.2.0 templating@1.2.13 templating-tools@1.0.4 tracker@1.1.0 diff --git a/tools/tool-testing/selftest.js b/tools/tool-testing/selftest.js index c2ae7feb44..1fd550f866 100644 --- a/tools/tool-testing/selftest.js +++ b/tools/tool-testing/selftest.js @@ -144,7 +144,8 @@ var ROOT_PACKAGES_TO_BUILD_IN_SANDBOX = [ "insecure", "standard-minifier-css", "standard-minifier-js", - "es5-shim" + "es5-shim", + "shell-server" ]; var setUpBuiltPackageTropohouse = function () { diff --git a/tools/upgraders.js b/tools/upgraders.js index 8691afc261..94528f9232 100644 --- a/tools/upgraders.js +++ b/tools/upgraders.js @@ -233,6 +233,12 @@ the guide about breaking changes here:`, files.rm_recursive(oldDevBundleLink); }, + "1.4.1-add-shell-server-package": function (projectContext) { + const packagesFile = projectContext.projectConstraintsFile; + packagesFile.addPackages(["shell-server"]); + packagesFile.writeIfModified(); + }, + //////////// // PLEASE. When adding new upgraders that print mesasges, follow the // examples for 0.9.0 and 0.9.1 above. Specifically, formatting From a78dde02254f9f2072e1db60e3fbeaa7ea26cc31 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 11:24:38 -0400 Subject: [PATCH 080/688] Make `meteor publish-for-arch` unnecessary in most cases (#7608) * Include process.{platform,arch} in .meteor-last-rebuild-version.json. This supports rebuilding binary npm packages published by completely different architectures, not just different versions of Node. * Make publish-for-arch unnecessary in most cases. * Don't rebuild binary packages when Node patch version changes. * Permit patch-compatible versions in .meteor-last-rebuild-version.json. This is a more general solution than simply discarding the patch version for currentVersions.versions.node, as I did in a previous commit. --- tools/isobuild/bundler.js | 4 ++ tools/isobuild/compiler.js | 21 +++++++- tools/isobuild/meteor-npm.js | 97 ++++++++++++++++++++++++++++-------- 3 files changed, 98 insertions(+), 24 deletions(-) diff --git a/tools/isobuild/bundler.js b/tools/isobuild/bundler.js index eb8b9dabd6..b507c349f4 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -260,6 +260,10 @@ export class NodeModulesDirectory { return meteorNpm.dependenciesArePortable(this.sourcePath); } + rebuildIfNonPortable() { + return meteorNpm.rebuildIfNonPortable(this.sourcePath); + } + getPreferredBundlePath(kind) { assert.ok(kind === "bundle" || kind === "isopack", diff --git a/tools/isobuild/compiler.js b/tools/isobuild/compiler.js index 9d9e9b632c..1de3c021b0 100644 --- a/tools/isobuild/compiler.js +++ b/tools/isobuild/compiler.js @@ -623,8 +623,25 @@ api.addAssets('${relPath}', 'client').`); return _.pick(symbol, ['name', 'testOnly']); }); - const isPortable = process.env.METEOR_FORCE_PORTABLE || - _.every(nodeModulesDirectories, nmd => nmd.isPortable()); + // By default, consider this isopack "portable" unless + // process.env.METEOR_ALLOW_NON_PORTABLE is truthy or the name of the + // package is "meteor-tool", in which case we determine portability by + // scanning node_modules directories for binary .node files. + // Non-portable packages must publish platform-specific builds using + // publish-for-arch, whereas portable packages can avoid running + // publish-for-arch and rely instead on the package consumer to rebuild + // binary npm dependencies when necessary. + let isPortable = true; + if (! process.env.METEOR_FORCE_PORTABLE) { + // Make sure we've rebuilt these npm packages according to the current + // process.{platform,arch,versions}. + _.each(nodeModulesDirectories, nmd => nmd.rebuildIfNonPortable()); + + if (process.env.METEOR_ALLOW_NON_PORTABLE || + isopk.name === "meteor-tool") { + isPortable = _.every(nodeModulesDirectories, nmd => nmd.isPortable()); + } + } // *** Consider npm dependencies and portability var arch = inputSourceArch.arch; diff --git a/tools/isobuild/meteor-npm.js b/tools/isobuild/meteor-npm.js index 16fc723a09..d8c9a21e32 100644 --- a/tools/isobuild/meteor-npm.js +++ b/tools/isobuild/meteor-npm.js @@ -156,12 +156,19 @@ meteorNpm.getProdPackageNames = function (nodeModulesDir) { }; const lastRebuildJSONFilename = ".meteor-last-rebuild-version.json"; + +const currentVersions = { + platform: process.platform, + arch: process.arch, + versions: {...process.versions}, +}; + const currentVersionsJSON = - JSON.stringify(process.versions, null, 2) + "\n"; + JSON.stringify(currentVersions, null, 2) + "\n"; function recordLastRebuildVersions(pkgDir) { - // Record the current process.versions so that we can avoid - // copying/rebuilding/renaming next time. + // Record the current process.{platform,arch,versions} so that we can + // avoid copying/rebuilding/renaming next time. files.writeFile( files.pathJoin(pkgDir, lastRebuildJSONFilename), currentVersionsJSON, @@ -169,6 +176,54 @@ function recordLastRebuildVersions(pkgDir) { ); } +// Returns true iff isSubtreeOf(currentVersions, versions), allowing +// valid semantic versions to differ in their patch versions. +function versionsAreCompatible(versions) { + import { parse } from "semver"; + + return isSubtreeOf(currentVersions, versions, (a, b) => { + // Technically already handled by isSubtreeOf, but doesn't hurt. + if (a === b) { + return true; + } + + if (! a || ! b) { + return false; + } + + const aType = typeof a; + const bType = typeof b; + + if (aType !== bType) { + return false; + } + + if (aType === "string") { + const aVer = parse(a); + const bVer = parse(b); + return aVer && bVer && + aVer.major === bVer.major && + aVer.minor === bVer.minor; + } + }); +} + +function rebuildVersionsAreCompatible(pkgPath) { + const versionFile = + files.pathJoin(pkgPath, lastRebuildJSONFilename); + + try { + var versions = JSON.parse(files.readFile(versionFile)); + } catch (e) { + if (! (e instanceof SyntaxError || + e.code === "ENOENT")) { + throw e; + } + } + + return versionsAreCompatible(versions); +} + // Rebuilds any binary dependencies in the given node_modules directory, // and returns true iff anything was rebuilt. meteorNpm.rebuildIfNonPortable = @@ -182,19 +237,7 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { return; } - const versionFile = - files.pathJoin(pkgPath, lastRebuildJSONFilename); - - try { - var versions = JSON.parse(files.readFile(versionFile)); - } catch (e) { - if (! (e instanceof SyntaxError || - e.code === "ENOENT")) { - throw e; - } - } - - if (_.isEqual(versions, process.versions)) { + if (rebuildVersionsAreCompatible(pkgPath)) { return; } @@ -457,16 +500,26 @@ var updateExistingNpmDirectory = function (packageName, newPackageNpmDir, npmDependencies); }; -function isSubtreeOf(subsetTree, supersetTree) { +function isSubtreeOf(subsetTree, supersetTree, predicate) { if (subsetTree === supersetTree) { return true; } - return _.isObject(subsetTree) && - _.isObject(supersetTree) && - _.every(subsetTree, (value, key) => { - return isSubtreeOf(value, supersetTree[key]); - }); + if (_.isObject(subsetTree)) { + return _.isObject(supersetTree) && + _.every(subsetTree, (value, key) => { + return isSubtreeOf(value, supersetTree[key], predicate); + }); + } + + if (_.isFunction(predicate)) { + const result = predicate(subsetTree, supersetTree); + if (typeof result === "boolean") { + return result; + } + } + + return false; } var createFreshNpmDirectory = function (packageName, newPackageNpmDir, From e5313e9144d0204c4e31a7fc12e4e83bb6c887ad Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 11:42:59 -0400 Subject: [PATCH 081/688] Update meteor-ecmascript-runtime to v0.2.9. --- scripts/dev-bundle-tool-package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index fd75a4d7a5..25e63dd000 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -21,7 +21,7 @@ var packageJson = { // 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. - "meteor-ecmascript-runtime": "0.2.6", + "meteor-ecmascript-runtime": "0.2.9", // 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). From d6cc3429fe8bb77e2d95629a4204fba4325370d4 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 11:43:08 -0400 Subject: [PATCH 082/688] Update meteor-babel to v0.12.0. --- scripts/dev-bundle-tool-package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 25e63dd000..53135a9a13 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -14,7 +14,7 @@ var packageJson = { npm: "3.10.5", "node-gyp": "3.4.0", "node-pre-gyp": "0.6.29", - "meteor-babel": "0.11.7", + "meteor-babel": "0.12.0", "meteor-promise": "0.7.2", fibers: "1.0.13", promise: "7.1.1", From 0122127aeebbeea64cec61f8566e01cc61f141ce Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 11:43:41 -0400 Subject: [PATCH 083/688] Bump $BUNDLE_VERSION to 4.2.6 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index 11f0d76f48..970f4b7882 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.5 +BUNDLE_VERSION=4.2.6 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From e9f6b2b4040f8f6b9902bfc9c79a9e5ea86b9c0d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 12:15:55 -0400 Subject: [PATCH 084/688] Bump package versions for 1.4.1-beta.1 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/less/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 74ae102d28..c099e9b2de 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-beta.0" + version: "1.2.11-beta.1" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 6e1e8e9dcb..23caff3a46 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0" + version: "1.3.0-beta.1" }); Package.onUse(function(api) { diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index df8b50745c..13bfffee0a 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-beta.0" + version: "1.2.4-beta.1" }); Package.registerBuildPlugin({ diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index 0174dcc23a..2fe26ccae6 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14", + version: "0.3.14-beta.1", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 2a87099b03..05659d950b 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-beta.0', + version: '0.5.8-beta.1', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 4c840c5e55..852f48aa20 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-beta.0" + version: "1.2.9-beta.1" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 6262f9481a..9fcf8ca25b 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-beta.0" + version: "1.1.14-beta.1" }); Package.onUse(function(api) { diff --git a/packages/less/package.js b/packages/less/package.js index 2a80110fd4..9a14a64080 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-beta.0', + version: '2.7.5-beta.1', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 015e41be53..a39c81422a 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.4.1-beta.0' + version: '1.4.1-beta.1' }); Package.includeTool(); diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 3415ca840b..18ebe08926 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-beta.0" + version: "1.2.14-beta.1" }); Npm.depends({ diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 4a91141576..0eb5729022 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-beta.0', + version: '1.2.0-beta.1', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 6f7ee445df..e0dbe6d6f0 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-beta.0', + version: '1.2.0-beta.1', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 5199039aee..69668c97eb 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-beta.0', + version: '1.1.12-beta.1', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 66e5953f0c..c045fd9f99 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-beta.0" + version: "2.513.5-beta.1" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 91744dab5d..045aa5ed30 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-beta.0' + version: '1.2.14-beta.1' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 4a1a61d1a0..787460f5b6 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-beta.0", + "version": "1.4.1-beta.1", "recommended": false, "official": false, "description": "Meteor" From 62ff1ec5ed961805c79a8d83492cf9fd82a25a86 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 16:08:57 -0400 Subject: [PATCH 085/688] Upgrade npm tar package to v2.2.1. --- scripts/dev-bundle-tool-package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 53135a9a13..c47a7c84fc 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -30,7 +30,7 @@ var packageJson = { semver: "4.1.0", request: "2.47.0", fstream: "https://github.com/meteor/fstream/tarball/cf4ea6c175355cec7bee38311e170d08c4078a5d", - tar: "1.0.2", + tar: "2.2.1", kexec: "2.0.2", "source-map": "0.5.3", "browserstack-webdriver": "2.41.1", From 1783932a5cc9822e9c2c05eb8baf9270012a3db5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 16:10:29 -0400 Subject: [PATCH 086/688] Bump $BUNDLE_VERSION to 4.2.7 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index 970f4b7882..40c9b22e95 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.6 +BUNDLE_VERSION=4.2.7 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From d808bc2a49dfca9975d27a16b37195b013a33be6 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 16:29:45 -0400 Subject: [PATCH 087/688] Bump package versions for 1.4.1-beta.2 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/less/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index c099e9b2de..2d5a8c4499 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-beta.1" + version: "1.2.11-beta.2" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 23caff3a46..2dfc8227ed 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-beta.1" + version: "1.3.0-beta.2" }); Package.onUse(function(api) { diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 13bfffee0a..0699e6f4c1 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-beta.1" + version: "1.2.4-beta.2" }); Package.registerBuildPlugin({ diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index 2fe26ccae6..d3c953311f 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-beta.1", + version: "0.3.14-beta.2", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 05659d950b..d6d7ac14fb 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-beta.1', + version: '0.5.8-beta.2', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 852f48aa20..83291d27dd 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-beta.1" + version: "1.2.9-beta.2" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 9fcf8ca25b..06827b142a 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-beta.1" + version: "1.1.14-beta.2" }); Package.onUse(function(api) { diff --git a/packages/less/package.js b/packages/less/package.js index 9a14a64080..1e438ab8ac 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-beta.1', + version: '2.7.5-beta.2', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index a39c81422a..e4c5d0fe79 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.4.1-beta.1' + version: '1.4.1-beta.2' }); Package.includeTool(); diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 18ebe08926..b1e8d37fa2 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-beta.1" + version: "1.2.14-beta.2" }); Npm.depends({ diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 0eb5729022..2ccbf76a63 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-beta.1', + version: '1.2.0-beta.2', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index e0dbe6d6f0..86575ed264 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-beta.1', + version: '1.2.0-beta.2', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 69668c97eb..1924610c9c 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-beta.1', + version: '1.1.12-beta.2', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index c045fd9f99..ad993ef3b4 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-beta.1" + version: "2.513.5-beta.2" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 045aa5ed30..addb980eb8 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-beta.1' + version: '1.2.14-beta.2' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 787460f5b6..9a3b7e2b93 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-beta.1", + "version": "1.4.1-beta.2", "recommended": false, "official": false, "description": "Meteor" From 38096aafc82323dcae11dc539fea9ecf4b5f4a88 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 18:30:17 -0400 Subject: [PATCH 088/688] Use --debug instead of --debug-brk for `meteor debug`. Breaking on the first statement in the program used to be the only way to get the debugger to stop at any breakpoints, but more recent versions of node-inspector (compatible with Node 4) do a much better job of stopping at breakpoints after the program starts. --- tools/inspector.js | 15 +++++++++++---- tools/runners/run-app.js | 6 +++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/inspector.js b/tools/inspector.js index b4265c8b72..21cc3ebaf6 100644 --- a/tools/inspector.js +++ b/tools/inspector.js @@ -295,13 +295,20 @@ function banner(debugPort) { return [ "", chalk.green([ - "Your application is now paused and ready for debugging!", + "Your application is now ready for debugging!", "", "To debug the server process using a graphical debugging interface, ", - "visit this URL in your web browser:" + "visit this URL in your web browser:", + "" ].join(EOL)), - chalk.cyan(proc.url), - EOL + chalk.cyan(" " + proc.url), + chalk.green([ + "", + "If your application is paused on a breakpoint but the code is not ", + "visible in the debugger, press the pause (||) button.", + "" + ].join(EOL)), + "" ].join(EOL); } diff --git a/tools/runners/run-app.js b/tools/runners/run-app.js index 8a5fa568eb..e0568e6cdc 100644 --- a/tools/runners/run-app.js +++ b/tools/runners/run-app.js @@ -240,9 +240,9 @@ _.extend(AppProcess.prototype, { if (self.debugPort) { attach = require('../inspector.js').start(self.debugPort, entryPoint); - // If you do opts.push("--debug-brk", port) it doesn't work on Windows - // for some reason - opts.push("--debug-brk=" + attach.suggestedDebugBrkPort); + // If you do opts.push("--debug", port) it doesn't work on Windows + // for some reason. + opts.push("--debug=" + attach.suggestedDebugBrkPort); } opts.push(entryPoint); From 0a58a934901674afc5bc2cb2a4407c1a7c62fd93 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 19:05:44 -0400 Subject: [PATCH 089/688] Allow tests to share .meteor/local/shell with apps. This change means `meteor shell` will now work when running tests with `meteor test`. --- tools/cli/commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 87473a5777..754e9b4535 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -1657,6 +1657,7 @@ function doTestCommand(options) { copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'bundler-cache'); copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'isopacks'); copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'plugin-cache'); + copyDirIntoTestRunnerApp(true, '.meteor', 'local', 'shell'); projectContext = new projectContextModule.ProjectContext(projectContextOptions); From fe761c53673a745a986457e951ccc39a08b89ba8 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Aug 2016 19:14:55 -0400 Subject: [PATCH 090/688] Bump package versions for 1.4.1-rc.0 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/less/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 2d5a8c4499..b95483b995 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-beta.2" + version: "1.2.11-rc.0" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 2dfc8227ed..f4f2cad40f 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-beta.2" + version: "1.3.0-rc.0" }); Package.onUse(function(api) { diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 0699e6f4c1..fdb37e4116 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-beta.2" + version: "1.2.4-rc.0" }); Package.registerBuildPlugin({ diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index d3c953311f..e10c6681b1 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-beta.2", + version: "0.3.14-rc.0", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index d6d7ac14fb..39c0c91abd 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-beta.2', + version: '0.5.8-rc.0', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 83291d27dd..021da91c1e 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-beta.2" + version: "1.2.9-rc.0" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 06827b142a..9c628af5d3 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-beta.2" + version: "1.1.14-rc.0" }); Package.onUse(function(api) { diff --git a/packages/less/package.js b/packages/less/package.js index 1e438ab8ac..bbbde2db14 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-beta.2', + version: '2.7.5-rc.0', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index e4c5d0fe79..69562c4416 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.4.1-beta.2' + version: '1.4.1-rc.0' }); Package.includeTool(); diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index b1e8d37fa2..281ebe3f75 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-beta.2" + version: "1.2.14-rc.0" }); Npm.depends({ diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 2ccbf76a63..c8e31fbe67 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-beta.2', + version: '1.2.0-rc.0', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 86575ed264..3a5337a974 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-beta.2', + version: '1.2.0-rc.0', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 1924610c9c..31509cec44 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-beta.2', + version: '1.1.12-rc.0', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index ad993ef3b4..3074a2c9b7 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-beta.2" + version: "2.513.5-rc.0" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index addb980eb8..1d899bdadb 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-beta.2' + version: '1.2.14-rc.0' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 9a3b7e2b93..14099a1ec2 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-beta.2", + "version": "1.4.1-rc.0", "recommended": false, "official": false, "description": "Meteor" From f9f94e21d10676aaa4a8a6809cb3bbc2fa60f536 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 15 Aug 2016 12:01:56 +1000 Subject: [PATCH 091/688] Fix issue with `_expirePasswordResetTokens` for #7534 Also added a test to actually execute this code --- packages/accounts-base/accounts_server.js | 2 +- packages/accounts-password/password_tests.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index f694b3a2bb..abeebd651a 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -1140,7 +1140,7 @@ Ap._expirePasswordResetTokens = function (oldestValidDate, userId) { { "services.password.reset.when": { $lt: +oldestValidDate } } ] }), { - $pull: { + $unset: { "services.password.reset": { $or: [ { when: { $lt: oldestValidDate } }, diff --git a/packages/accounts-password/password_tests.js b/packages/accounts-password/password_tests.js index fcabdfe8d3..61c78060e4 100644 --- a/packages/accounts-password/password_tests.js +++ b/packages/accounts-password/password_tests.js @@ -1468,6 +1468,20 @@ if (Meteor.isServer) (function () { }, /Incorrect password/); }); + Tinytest.add( + 'passwords - reset tokens get cleaned up', + function (test) { + var email = test.id + '-intercept@example.com'; + var userId = Accounts.createUser({email: email, password: 'password'}); + Accounts.sendResetPasswordEmail(userId, email); + test.isTrue(!!Meteor.users.findOne(userId).services.password.reset); + + Accounts._expirePasswordResetTokens(new Date(), userId); + + test.isUndefined(Meteor.users.findOne(userId).services.password.reset); + } + ) + // We should be able to change the username Tinytest.add("passwords - change username", function (test) { var username = Random.id(); From bff8d742dd377cd054cac9f7bf17e7365e656cb9 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 11:12:34 -0400 Subject: [PATCH 092/688] Update History.md with more changes in 1.4.1. --- History.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/History.md b/History.md index aa4cff3eae..f05d1769cc 100644 --- a/History.md +++ b/History.md @@ -2,15 +2,41 @@ ## v1.4.1 +* The `meteor publish-for-arch` command is no longer necessary when + publishing Meteor packages with binary npm dependencies. Instead, binary + dependencies will be rebuilt automatically on the installation side. + Meteor package authors are not responsible for failures due to compiler + toolchain misconfiguration, and any compilation problems with the + underlying npm packages should be taken up with the authors of those + packages. That said, if a Meteor package author really needs or wants to + continue using `meteor publish-for-arch`, she should publish her package + using an older release: e.g. `meteor --release 1.4 publish`. + [#7608](https://github.com/meteor/meteor/pull/7608) + +* The `npm-bcrypt` package now uses a pure-JavaScript implementation by + default, but will prefer the native `bcrypt` implementation if it is + installed in the application's `node_modules` directory. In other words, + run `meteor install --save bcrypt` in your application if you need or + want to use the native implementation of `bcrypt`. + [#7595](https://github.com/meteor/meteor/pull/7595) + * After Meteor packages are downloaded from Atmosphere, they will now be extracted using native `tar` or `7z.exe` on Windows, instead of the https://www.npmjs.com/package/tar library, for a significant performance improvement. [#7457](https://github.com/meteor/meteor/pull/7457) +* The npm `tar` package has been upgraded to 2.2.1, though it is now only + used as a fallback after native `tar` and/or `7z.exe`. + * The progress indicator now distinguishes between downloading, extracting, and loading newly-installed Meteor packages, instead of lumping all of that work into a "downloading" status message. +* Background Meteor updates will no longer modify the `~/.meteor/meteor` + symbolic link (or `AppData\Local\.meteor\meteor.bat` on Windows). + Instead, developers must explicitly type `meteor update` to begin using + a new version of the `meteor` script. + * Password Reset tokens now expire (after 3 days by default -- can be modified via `Accounts.config({ passwordResetTokenExpirationInDays: ...}`). [PR #7534](https://github.com/meteor/meteor/pull/7534) * The `google` package now uses the `email` scope as a mandatory field instead @@ -48,6 +74,27 @@ Node 4 `crypto` library natively supports the `aes-128-gcm` algorithm. [#7548](https://github.com/meteor/meteor/pull/7548) +* The server-side component of the `meteor shell` command has been moved + into a Meteor package, so that it can be developed independently from + the Meteor release process, thanks to version unpinning. + [#7624](https://github.com/meteor/meteor/pull/7624) + +* The `meteor shell` command now works when running `meteor test`. + +* The `meteor debug` command no longer pauses at the first statement + in the Node process, yet still reliably stops at custom breakpoints + it encounters later. + +* The `meteor-babel` package has been upgraded to 0.12.0. + +* The `meteor-ecmascript-runtime` package has been upgraded to 0.2.9, to + support several additional [stage 4 + proposals](https://github.com/meteor/ecmascript-runtime/pull/4). + +* A bug that prevented @-scoped npm packages from getting bundled for + deployed apps has been fixed. + [#7609](https://github.com/meteor/meteor/pull/7609). + ## v1.4.0.1 * Fix issue with the 1.4 tool springboarding to older releases (see [Issue #7491](https://github.com/meteor/meteor/issues/7491)) From 65b3e60d67f25fc80edeaf244e5810ddf585e75f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 11:13:39 -0400 Subject: [PATCH 093/688] Bump package versions for 1.4.1-rc.1 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/less/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index b95483b995..26313ac8f9 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.0" + version: "1.2.11-rc.1" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index f4f2cad40f..5a850f50eb 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.0" + version: "1.3.0-rc.1" }); Package.onUse(function(api) { diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index fdb37e4116..5eb3e15186 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.0" + version: "1.2.4-rc.1" }); Package.registerBuildPlugin({ diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index e10c6681b1..f7a017db03 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.0", + version: "0.3.14-rc.1", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 39c0c91abd..3e11e7c525 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.0', + version: '0.5.8-rc.1', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 021da91c1e..0d3b829c65 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.0" + version: "1.2.9-rc.1" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 9c628af5d3..2ed6ab2019 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.0" + version: "1.1.14-rc.1" }); Package.onUse(function(api) { diff --git a/packages/less/package.js b/packages/less/package.js index bbbde2db14..5e54964c3f 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.0', + version: '2.7.5-rc.1', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 69562c4416..cebecac81d 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.4.1-rc.0' + version: '1.4.1-rc.1' }); Package.includeTool(); diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 281ebe3f75..085ff3239c 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.0" + version: "1.2.14-rc.1" }); Npm.depends({ diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index c8e31fbe67..33182a0fec 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.0', + version: '1.2.0-rc.1', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 3a5337a974..32839fd828 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.0', + version: '1.2.0-rc.1', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 31509cec44..a51dabfe59 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.0', + version: '1.1.12-rc.1', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 3074a2c9b7..9f887e11e4 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.0" + version: "2.513.5-rc.1" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 1d899bdadb..bb67773bc8 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.0' + version: '1.2.14-rc.1' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 14099a1ec2..97e91270cb 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.0", + "version": "1.4.1-rc.1", "recommended": false, "official": false, "description": "Meteor" From 351e958d6c2d9f747e9fb91d8bb34b7e0d2cb229 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 13:39:26 -0400 Subject: [PATCH 094/688] Mention relaxing .meteor-last-rebuild-version.json comparisons. --- History.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/History.md b/History.md index f05d1769cc..9508b5b20f 100644 --- a/History.md +++ b/History.md @@ -13,6 +13,12 @@ using an older release: e.g. `meteor --release 1.4 publish`. [#7608](https://github.com/meteor/meteor/pull/7608) +* The `.meteor-last-rebuild-version.json` files that determine if a binary + npm package needs to be rebuilt now include more information from the + `process` object, namely `process.{platform,arch,versions}` instead of + just `process.versions`. Note also that the comparison of versions now + ignores differences in patch versions, to avoid needless rebuilds. + * The `npm-bcrypt` package now uses a pure-JavaScript implementation by default, but will prefer the native `bcrypt` implementation if it is installed in the application's `node_modules` directory. In other words, From f6a52788f0aefedb60d597e27577cf0cab614a0d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 13:34:00 -0400 Subject: [PATCH 095/688] Remove BrowserStack from dev bundle. --- scripts/ci.sh | 2 +- scripts/dev-bundle-tool-package.js | 1 - scripts/generate-dev-bundle.sh | 12 ----- tools/tool-testing/selftest.js | 73 +++++++++++++++++++++++------- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/scripts/ci.sh b/scripts/ci.sh index d81fa968c4..3004d2a75d 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -7,7 +7,7 @@ export EMACS=t # Since PhantomJS has been removed from dev_bundle/lib/node_modules # (#6905), but self-test still needs it, install it now. -./meteor npm install -g phantomjs-prebuilt +./meteor npm install -g phantomjs-prebuilt browserstack-webdriver # run different jobs based on CicleCI parallel container index case $CIRCLE_NODE_INDEX in diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index c47a7c84fc..9d5aa5b600 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -33,7 +33,6 @@ var packageJson = { tar: "2.2.1", kexec: "2.0.2", "source-map": "0.5.3", - "browserstack-webdriver": "2.41.1", "node-inspector": "0.12.8", chalk: "0.5.1", sqlite3: "3.1.3", diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index e439817b2d..2790ad3a43 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -120,9 +120,6 @@ delete () { rm -rf "$1" } -delete browserstack-webdriver/docs -delete browserstack-webdriver/lib/test - delete sqlite3/deps delete wordwrap/test delete moment/min @@ -133,15 +130,6 @@ find . -path '*/esprima-fb/test' | xargs rm -rf cd "$DIR/lib/node_modules/fibers/bin" shrink_fibers -# Download BrowserStackLocal binary. -BROWSER_STACK_LOCAL_URL="https://browserstack-binaries.s3.amazonaws.com/BrowserStackLocal-07-03-14-$OS-$ARCH.gz" - -cd "$DIR/build" -curl -O $BROWSER_STACK_LOCAL_URL -gunzip BrowserStackLocal* -mv BrowserStackLocal* BrowserStackLocal -mv BrowserStackLocal "$DIR/bin/" - # Sanity check to see if we're not breaking anything by replacing npm INSTALLED_NPM_VERSION=$(cat "$DIR/lib/node_modules/npm/package.json" | xargs -0 node -e "console.log(JSON.parse(process.argv[1]).version)") diff --git a/tools/tool-testing/selftest.js b/tools/tool-testing/selftest.js index 1fd550f866..f8a0b732d0 100644 --- a/tools/tool-testing/selftest.js +++ b/tools/tool-testing/selftest.js @@ -3,7 +3,6 @@ var util = require('util'); var Future = require('fibers/future'); var fiberHelpers = require('../utils/fiber-helpers.js'); var child_process = require('child_process'); -var webdriver = require('browserstack-webdriver'); var files = require('../fs/files.js'); var utils = require('../utils/utils.js'); @@ -13,6 +12,7 @@ var archinfo = require('../utils/archinfo.js'); var config = require('../meteor-services/config.js'); var buildmessage = require('../utils/buildmessage.js'); var execFileSync = require('../utils/processes.js').execFileSync; +var { getUrlWithResuming } = require("../utils/http-helpers.js"); var Builder = require('../isobuild/builder.js').default; var catalog = require('../packaging/catalog/catalog.js'); @@ -29,20 +29,25 @@ var upgraders = require('../upgraders.js'); require("../tool-env/install-runtime.js"); -try { - var phantomPath = require.resolve('phantomjs-prebuilt'); -} catch (e) { - throw new Error([ - "Please install PhantomJS by running the following command:", - "", - " /path/to/meteor npm install -g phantomjs-prebuilt", - "", - "Where `/path/to/meteor` is the executable you used to run this self-test.", - "" - ].join("\n")); +function checkTestOnlyDependency(name) { + try { + var absPath = require.resolve(name); + } catch (e) { + throw new Error([ + "Please install " + name + " by running the following command:", + "", + " /path/to/meteor npm install -g " + name, + "", + "Where `/path/to/meteor` is the executable you used to run this self-test.", + "" + ].join("\n")); + } + + return require(absPath); } -var phantomjs = require(phantomPath); +var phantomjs = checkTestOnlyDependency("phantomjs-prebuilt"); +var webdriver = checkTestOnlyDependency('browserstack-webdriver'); // To allow long stack traces that cross async boundaries require('longjohn'); @@ -1077,10 +1082,8 @@ _.extend(BrowserStackClient.prototype, { }, _launchBrowserStackTunnel: function (callback) { - var self = this; - var browserStackPath = - files.pathJoin(files.getDevBundle(), 'bin', 'BrowserStackLocal'); - files.chmod(browserStackPath, 0o755); + const self = this; + const browserStackPath = ensureBrowserStack(); var args = [ browserStackPath, @@ -1105,6 +1108,42 @@ _.extend(BrowserStackClient.prototype, { } }); +function ensureBrowserStack() { + const browserStackPath = files.pathJoin( + files.getDevBundle(), + 'bin', + 'BrowserStackLocal' + ); + + const browserStackStat = files.statOrNull(browserStackPath); + if (! browserStackStat) { + const host = "browserstack-binaries.s3.amazonaws.com"; + const OS = process.platform === "darwin" ? "osx" : "linux"; + const ARCH = process.arch === "x64" ? "x86_64" : "i686"; + const tarGz = `BrowserStackLocal-07-03-14-${OS}-${ARCH}.gz`; + const url = `https:\/\/${host}/${tarGz}`; + + buildmessage.enterJob("downloading BrowserStack binaries", () => { + return new Promise((resolve, reject) => { + const browserStackStream = + files.createWriteStream(browserStackPath); + + browserStackStream.on("error", reject); + browserStackStream.on("end", resolve); + + const gunzip = require("zlib").createGunzip(); + gunzip.pipe(browserStackStream); + gunzip.write(getUrlWithResuming(url)); + gunzip.end(); + }).await(); + }); + } + + files.chmod(browserStackPath, 0o755); + + return browserStackPath; +} + /////////////////////////////////////////////////////////////////////////////// // Run /////////////////////////////////////////////////////////////////////////////// From 8aff09bec5fa8e81081e1f2a3d9c874671c0a773 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 13:35:17 -0400 Subject: [PATCH 096/688] Remove unnecessary sqlite3 dependencies from dev bundle. --- scripts/generate-dev-bundle.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 2790ad3a43..6bb9ec48d5 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -121,6 +121,8 @@ delete () { } delete sqlite3/deps +delete sqlite3/node_modules/nan +delete sqlite3/node_modules/node-pre-gyp delete wordwrap/test delete moment/min From 99004c08268b266d9a6e1b1204e8c9e95305c21d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 13:35:31 -0400 Subject: [PATCH 097/688] Remove npm/test from dev bundle. --- scripts/generate-dev-bundle.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 6bb9ec48d5..9c5e6d2cf2 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -120,6 +120,7 @@ delete () { rm -rf "$1" } +delete npm/test delete sqlite3/deps delete sqlite3/node_modules/nan delete sqlite3/node_modules/node-pre-gyp From da0e944c149af18e38ffebfe466172ee7b1aec68 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 14:20:39 -0400 Subject: [PATCH 098/688] Avoid installing an extra copy of node-gyp in the dev bundle. --- scripts/generate-dev-bundle.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 9c5e6d2cf2..ec3aa0d522 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -121,6 +121,11 @@ delete () { } delete npm/test +delete npm/node_modules/node-gyp +pushd npm/node_modules +ln -s ../../node-gyp ./ +popd + delete sqlite3/deps delete sqlite3/node_modules/nan delete sqlite3/node_modules/node-pre-gyp From b2e2d0651be672a4be085cf705d0eb6261650deb Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 14:21:13 -0400 Subject: [PATCH 099/688] Don't install node-gyp or node-pre-gyp in server bundle. These packages need to be installed when we run `npm install` in `bundle/programs/server` (which this commit ensures), but they don't need to be part of the dev bundle. --- scripts/dev-bundle-server-package.js | 2 -- scripts/generate-dev-bundle.sh | 18 +++++++++--------- tools/isobuild/bundler.js | 3 +++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/scripts/dev-bundle-server-package.js b/scripts/dev-bundle-server-package.js index c4641e5125..6c03d52c98 100644 --- a/scripts/dev-bundle-server-package.js +++ b/scripts/dev-bundle-server-package.js @@ -9,8 +9,6 @@ var packageJson = { // Version is not important but is needed to prevent warnings. version: "0.0.0", dependencies: { - "node-gyp": "3.4.0", - "node-pre-gyp": "0.6.29", "meteor-promise": "0.7.2", fibers: "1.0.13", promise: "7.1.1", diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index ec3aa0d522..fbc8d0756d 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -68,15 +68,6 @@ mkdir -p "${DIR}/server-lib/node_modules" # This ignores the stuff in node_modules/.bin, but that's OK. cp -R node_modules/* "${DIR}/server-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}/server-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" - mkdir -p "${DIR}/etc" mv package.json npm-shrinkwrap.json "${DIR}/etc/" @@ -104,6 +95,15 @@ 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/isobuild/bundler.js b/tools/isobuild/bundler.js index b507c349f4..b3686c7b80 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -2145,6 +2145,9 @@ class ServerTarget extends JsImageTarget { serverPkgJson.scripts = serverPkgJson.scripts || {}; serverPkgJson.scripts.install = "node npm-rebuild.js"; + serverPkgJson.dependencies["node-gyp"] = "3.4.0"; + serverPkgJson.dependencies["node-pre-gyp"] = "0.6.29"; + builder.write('package.json', { data: new Buffer( JSON.stringify(serverPkgJson, null, 2) + "\n", From da88a4afe0b68fb780b1b09da56f6f83311296d8 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 14:22:31 -0400 Subject: [PATCH 100/688] Remove cordova-app-hello-world from dev bundle. This package is depended upon by `cordova-lib`, and npm@3 hoists it to the top-level dev_bundle/lib/node_modules directory. We don't use this example app in Meteor, so we don't need it in the dev bundle. If it is ever needed, developers can run meteor npm install -g cordova-app-hello-world To include it in the dev bundle. It would be really great if we could remove cordova-lib's extra copy of npm, but that will probably have to wait until they update to npm@3. --- scripts/generate-dev-bundle.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index fbc8d0756d..d37a3e1f04 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -131,6 +131,7 @@ delete sqlite3/node_modules/nan delete sqlite3/node_modules/node-pre-gyp delete wordwrap/test delete moment/min +delete cordova-app-hello-world # Remove esprima tests to reduce the size of the dev bundle find . -path '*/esprima-fb/test' | xargs rm -rf From ccb56dd45c2dca689ff33d9a9712b882b6864d3e Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 14:34:07 -0400 Subject: [PATCH 101/688] Bump $BUNDLE_VERSION to 4.2.8 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index 40c9b22e95..e97732eaaf 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.7 +BUNDLE_VERSION=4.2.8 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From 9478f35fa4116dc3ef35ef7fcd4ddc19ca97e1ee Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Aug 2016 14:52:02 -0400 Subject: [PATCH 102/688] Bump package versions for 1.4.1-rc.2 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/less/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 26313ac8f9..3ae99964e7 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.1" + version: "1.2.11-rc.2" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 5a850f50eb..3c58895926 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.1" + version: "1.3.0-rc.2" }); Package.onUse(function(api) { diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 5eb3e15186..749fe6a3a3 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.1" + version: "1.2.4-rc.2" }); Package.registerBuildPlugin({ diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index f7a017db03..4862050853 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.1", + version: "0.3.14-rc.2", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 3e11e7c525..d7efc4f657 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.1', + version: '0.5.8-rc.2', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 0d3b829c65..0774c250f1 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.1" + version: "1.2.9-rc.2" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 2ed6ab2019..0461c9d597 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.1" + version: "1.1.14-rc.2" }); Package.onUse(function(api) { diff --git a/packages/less/package.js b/packages/less/package.js index 5e54964c3f..f300bb8c0c 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.1', + version: '2.7.5-rc.2', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index cebecac81d..abd793329c 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.4.1-rc.1' + version: '1.4.1-rc.2' }); Package.includeTool(); diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 085ff3239c..75a9efae0b 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.1" + version: "1.2.14-rc.2" }); Npm.depends({ diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 33182a0fec..07b9beb306 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.1', + version: '1.2.0-rc.2', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 32839fd828..de9de6821d 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.1', + version: '1.2.0-rc.2', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index a51dabfe59..81c7b190ec 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.1', + version: '1.1.12-rc.2', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 9f887e11e4..158739a04d 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.1" + version: "2.513.5-rc.2" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index bb67773bc8..148470e214 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.1' + version: '1.2.14-rc.2' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 97e91270cb..365db9f7be 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.1", + "version": "1.4.1-rc.2", "recommended": false, "official": false, "description": "Meteor" From b45f733209a13e9545f3758ee063757572dddc3f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 12:47:19 -0400 Subject: [PATCH 103/688] Upgrade Node to 4.5.0. https://nodejs.org/en/blog/release/v4.5.0/ --- History.md | 2 ++ scripts/build-dev-bundle-common.sh | 2 +- scripts/generate-dev-bundle.ps1 | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 9508b5b20f..b8118e0cb8 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,8 @@ ## v1.4.1 +* Node has been upgraded to 4.5.0. + * The `meteor publish-for-arch` command is no longer necessary when publishing Meteor packages with binary npm dependencies. Instead, binary dependencies will be rebuilt automatically on the installation side. diff --git a/scripts/build-dev-bundle-common.sh b/scripts/build-dev-bundle-common.sh index 325f6f4994..64265d26fa 100644 --- a/scripts/build-dev-bundle-common.sh +++ b/scripts/build-dev-bundle-common.sh @@ -6,7 +6,7 @@ set -u UNAME=$(uname) ARCH=$(uname -m) MONGO_VERSION=3.2.6 -NODE_VERSION=4.4.7 +NODE_VERSION=4.5.0 NPM_VERSION=3.10.5 if [ "$UNAME" == "Linux" ] ; then diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 6e9ec54562..f1f6f97c84 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -2,7 +2,7 @@ # use 32bit by default $PLATFORM = "windows_x86" $MONGO_VERSION = "3.2.6" -$NODE_VERSION = "4.4.7" +$NODE_VERSION = "4.5.0" $NPM_VERSION = "3.10.5" $PYTHON_VERSION = "2.7.10" # For node-gyp From ca51c8fd87c32adc2057e6b43d940a3abcf189eb Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 12:50:23 -0400 Subject: [PATCH 104/688] Upgrade npm to 3.10.6. https://github.com/npm/npm/blob/master/CHANGELOG.md#v3106-2016-07-07 --- History.md | 2 ++ scripts/build-dev-bundle-common.sh | 2 +- scripts/dev-bundle-tool-package.js | 2 +- scripts/generate-dev-bundle.ps1 | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index b8118e0cb8..5ce9cff087 100644 --- a/History.md +++ b/History.md @@ -4,6 +4,8 @@ * Node has been upgraded to 4.5.0. +* `npm` has been upgraded to 3.10.6. + * The `meteor publish-for-arch` command is no longer necessary when publishing Meteor packages with binary npm dependencies. Instead, binary dependencies will be rebuilt automatically on the installation side. diff --git a/scripts/build-dev-bundle-common.sh b/scripts/build-dev-bundle-common.sh index 64265d26fa..5e2e858e55 100644 --- a/scripts/build-dev-bundle-common.sh +++ b/scripts/build-dev-bundle-common.sh @@ -7,7 +7,7 @@ UNAME=$(uname) ARCH=$(uname -m) MONGO_VERSION=3.2.6 NODE_VERSION=4.5.0 -NPM_VERSION=3.10.5 +NPM_VERSION=3.10.6 if [ "$UNAME" == "Linux" ] ; then if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 9d5aa5b600..7daff12cda 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -11,7 +11,7 @@ var packageJson = { dependencies: { // Explicit dependency because we are replacing it with a bundled version // and we want to make sure there are no dependencies on a higher version - npm: "3.10.5", + npm: "3.10.6", "node-gyp": "3.4.0", "node-pre-gyp": "0.6.29", "meteor-babel": "0.12.0", diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index f1f6f97c84..08f034f87e 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -3,7 +3,7 @@ $PLATFORM = "windows_x86" $MONGO_VERSION = "3.2.6" $NODE_VERSION = "4.5.0" -$NPM_VERSION = "3.10.5" +$NPM_VERSION = "3.10.6" $PYTHON_VERSION = "2.7.10" # For node-gyp # take it form the environment if exists From d28fe76851afb2d196cb44aac1b1e23943cf1a57 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 12:51:22 -0400 Subject: [PATCH 105/688] Upgrade Windows bundled Python version to 2.7.12. --- scripts/generate-dev-bundle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate-dev-bundle.ps1 b/scripts/generate-dev-bundle.ps1 index 08f034f87e..61953f70d4 100644 --- a/scripts/generate-dev-bundle.ps1 +++ b/scripts/generate-dev-bundle.ps1 @@ -4,7 +4,7 @@ $PLATFORM = "windows_x86" $MONGO_VERSION = "3.2.6" $NODE_VERSION = "4.5.0" $NPM_VERSION = "3.10.6" -$PYTHON_VERSION = "2.7.10" # For node-gyp +$PYTHON_VERSION = "2.7.12" # For node-gyp # take it form the environment if exists if (Test-Path env:PLATFORM) { From b7bab0eefa5be3924d8ac4af3ec46ac2a826ff7c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 12:52:04 -0400 Subject: [PATCH 106/688] Bump $BUNDLE_VERSION to 4.2.9 before rebuilding dev bundle. --- meteor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteor b/meteor index e97732eaaf..03d4169b23 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.2.8 +BUNDLE_VERSION=4.2.9 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From afbddc428b5d3443dd0e8514f67f6685967d6c2f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 13:05:54 -0400 Subject: [PATCH 107/688] Bump package versions for 1.4.1-rc.3 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/babel-compiler/package.js | 2 +- packages/babel-runtime/package.js | 2 +- packages/caching-compiler/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ddp-client/package.js | 2 +- packages/ddp-server/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/email/package.js | 2 +- packages/es5-shim/package.js | 4 ++-- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/http/package.js | 2 +- packages/jshint/package.js | 2 +- packages/less/package.js | 2 +- packages/logging/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/meteor/package.js | 2 +- packages/minifier-css/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/modules-runtime/package.js | 2 +- packages/modules/package.js | 2 +- packages/mongo/package.js | 2 +- packages/npm-bcrypt/package.js | 2 +- packages/npm-mongo/package.js | 2 +- packages/promise/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- packages/webapp/package.js | 2 +- packages/xmlbuilder/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 36 files changed, 37 insertions(+), 37 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 3ae99964e7..260a76316e 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.2" + version: "1.2.11-rc.3" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 3c58895926..b36d3d6cb1 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.2" + version: "1.3.0-rc.3" }); Package.onUse(function(api) { diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 1a6c4306d2..6075a69f37 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,7 +6,7 @@ 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.9.0' + version: '6.9.1-rc.3' }); Npm.depends({ diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index 8f68486e18..5a4bd373fd 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '0.1.10', + version: '0.1.11-rc.3', documentation: 'README.md' }); diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 06b1d6d4cd..3c30b7709d 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.6', + version: '1.1.7-rc.3', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 749fe6a3a3..2a8ff5b6b6 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.2" + version: "1.2.4-rc.3" }); Package.registerBuildPlugin({ diff --git a/packages/ddp-client/package.js b/packages/ddp-client/package.js index cc0cb2a6d3..cd4fdd4925 100644 --- a/packages/ddp-client/package.js +++ b/packages/ddp-client/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data client", - version: '1.3.0', + version: '1.3.1-rc.3', documentation: null }); diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index c2a7731e23..36121a3dbf 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data server", - version: '1.3.9', + version: '1.3.10-rc.3', documentation: null }); diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index 4862050853..eab3b6dd90 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.2", + version: "0.3.14-rc.3", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index d7efc4f657..9d672879b1 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.2', + version: '0.5.8-rc.3', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/email/package.js b/packages/email/package.js index ad1dc37e5d..8fdce2fa5b 100644 --- a/packages/email/package.js +++ b/packages/email/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Send email messages", - version: "1.1.16" + version: "1.1.17-rc.3" }); Npm.depends({ diff --git a/packages/es5-shim/package.js b/packages/es5-shim/package.js index 30e5b6451a..aead376fb7 100644 --- a/packages/es5-shim/package.js +++ b/packages/es5-shim/package.js @@ -1,12 +1,12 @@ Package.describe({ name: "es5-shim", - version: "4.6.13", + version: "4.6.14-rc.3", summary: "Shims and polyfills to improve ECMAScript 5 support", documentation: "README.md" }); Npm.depends({ - "es5-shim": "4.5.7" + "es5-shim": "4.5.9" }); Package.onUse(function(api) { diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 0774c250f1..1a05254e7d 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.2" + version: "1.2.9-rc.3" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 0461c9d597..31262757a4 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.2" + version: "1.1.14-rc.3" }); Package.onUse(function(api) { diff --git a/packages/http/package.js b/packages/http/package.js index 745d6bc218..4f62bfa2fb 100644 --- a/packages/http/package.js +++ b/packages/http/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Make HTTP calls to remote servers", - version: '1.2.8' + version: '1.2.9-rc.3' }); Npm.depends({ diff --git a/packages/jshint/package.js b/packages/jshint/package.js index 50c54dc46f..653b3ec043 100644 --- a/packages/jshint/package.js +++ b/packages/jshint/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'jshint', - version: '1.1.5', + version: '1.1.6-rc.3', summary: 'Lint all your JavaScript files with JSHint.', documentation: 'README.md' }); diff --git a/packages/less/package.js b/packages/less/package.js index f300bb8c0c..fd76de85ce 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.2', + version: '2.7.5-rc.3', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/logging/package.js b/packages/logging/package.js index c3a9806e24..0491a529b1 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Logging facility.", - version: '1.1.14' + version: '1.1.15-rc.3' }); Npm.depends({ diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index abd793329c..62c1db8d86 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.4.1-rc.2' + version: '1.4.1-rc.3' }); Package.includeTool(); diff --git a/packages/meteor/package.js b/packages/meteor/package.js index f4067cf16e..70330120f3 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: "Core Meteor environment", - version: '1.2.16' + version: '1.2.17-rc.3' }); Package.registerBuildPlugin({ diff --git a/packages/minifier-css/package.js b/packages/minifier-css/package.js index 3de369f110..58e08f06b2 100644 --- a/packages/minifier-css/package.js +++ b/packages/minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "CSS minifier", - version: "1.2.13" + version: "1.2.14-rc.3" }); Npm.depends({ diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 75a9efae0b..c42ee5bbb7 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.2" + version: "1.2.14-rc.3" }); Npm.depends({ diff --git a/packages/modules-runtime/package.js b/packages/modules-runtime/package.js index 9ef594d341..f393599f80 100644 --- a/packages/modules-runtime/package.js +++ b/packages/modules-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules-runtime", - version: "0.7.5", + version: "0.7.6-rc.3", summary: "CommonJS module system", git: "https://github.com/benjamn/install", documentation: "README.md" diff --git a/packages/modules/package.js b/packages/modules/package.js index 2315ab1943..2353d6d36b 100644 --- a/packages/modules/package.js +++ b/packages/modules/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules", - version: "0.7.5", + version: "0.7.6-rc.3", summary: "CommonJS module system", documentation: "README.md" }); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index 34065c55ea..9b6a93772b 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.10' + version: '1.1.11-rc.3' }); Npm.depends({ diff --git a/packages/npm-bcrypt/package.js b/packages/npm-bcrypt/package.js index 61f5431c66..7fdc4da1cb 100644 --- a/packages/npm-bcrypt/package.js +++ b/packages/npm-bcrypt/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Wrapper around the bcrypt npm package", - version: "0.9.0", + version: "0.9.1-rc.3", documentation: null }); diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 92c312d7fe..98ecf7261c 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,7 +3,7 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.45', + version: '1.5.46-rc.3', documentation: null }); diff --git a/packages/promise/package.js b/packages/promise/package.js index a808ffae15..3befaa2623 100644 --- a/packages/promise/package.js +++ b/packages/promise/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "promise", - version: "0.8.3", + version: "0.8.4-rc.3", summary: "ECMAScript 2015 Promise polyfill with Fiber support", git: "https://github.com/meteor/promise", documentation: "README.md" diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 07b9beb306..3651d99c68 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.2', + version: '1.2.0-rc.3', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index de9de6821d..88d2fd0ba1 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.2', + version: '1.2.0-rc.3', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 81c7b190ec..5aa237b948 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.2', + version: '1.1.12-rc.3', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 158739a04d..349cf4ce10 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.2" + version: "2.513.5-rc.3" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 148470e214..12eeb9ff25 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.2' + version: '1.2.14-rc.3' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 5675570b12..3e000291b2 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.10' + version: '1.3.11-rc.3' }); Npm.depends({connect: "2.30.2", diff --git a/packages/xmlbuilder/package.js b/packages/xmlbuilder/package.js index 619eabb6ba..aa198437c8 100644 --- a/packages/xmlbuilder/package.js +++ b/packages/xmlbuilder/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "An XML builder for node.js similar to java-xmlbuilder.", - version: '2.5.13' + version: '2.5.14-rc.3' }); Npm.depends({ diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 365db9f7be..0a88fb4b37 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.2", + "version": "1.4.1-rc.3", "recommended": false, "official": false, "description": "Meteor" From 7c019139f596bfa44ca734d85cd4cd50f9f52c53 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 16:26:52 -0400 Subject: [PATCH 108/688] Update es5-shim shrinkwrap file. --- packages/es5-shim/.npm/package/npm-shrinkwrap.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/es5-shim/.npm/package/npm-shrinkwrap.json b/packages/es5-shim/.npm/package/npm-shrinkwrap.json index 5e557de55d..cf6fd2e3a9 100644 --- a/packages/es5-shim/.npm/package/npm-shrinkwrap.json +++ b/packages/es5-shim/.npm/package/npm-shrinkwrap.json @@ -1,9 +1,9 @@ { "dependencies": { "es5-shim": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.7.tgz", - "from": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.7.tgz" + "version": "4.5.9", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.9.tgz", + "from": "es5-shim@4.5.9" } } } From c5809a4a1c90a4878a6883639e2d1b6da0698aca Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 16:23:48 -0400 Subject: [PATCH 109/688] Allow files.cp_r to copy non-directories. --- tools/fs/files.js | 86 +++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index 02f3d9ab15..d474c03a61 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -434,9 +434,7 @@ files.mkdir_p = function (dir, mode) { return pathIsDirectory(p); }; -// Roughly like cp -R. 'from' should be a directory. 'to' can either -// be a directory, or it can not exist (in which case it will be -// created with mkdir_p). +// Roughly like cp -R. // // The output files will be readable and writable by everyone that the umask // allows, and executable by everyone (modulo umask) if the original file was @@ -450,49 +448,55 @@ files.mkdir_p = function (dir, mode) { // If options.ignore is present, it should be a list of regexps. Any // file whose basename matches one of the regexps, before // transformation, will be skipped. -files.cp_r = function (from, to, options) { - options = options || {}; +files.cp_r = function(from, to, options = {}) { + from = files.pathResolve(from); - var absFrom = files.pathResolve(from); - files.mkdir_p(to, 0o755); + const stat = options.preserveSymlinks + ? files.lstat(from) + : files.stat(from); - _.each(files.readdir(from), function (f) { - if (_.any(options.ignore || [], function (pattern) { - return f.match(pattern); - })) { - return; - } + if (stat.isDirectory()) { + files.mkdir_p(to, 0o755); - var fullFrom = files.pathJoin(from, f); - if (options.transformFilename) { - f = options.transformFilename(f); - } - var fullTo = files.pathJoin(to, f); - var stats = options.preserveSymlinks - ? files.lstat(fullFrom) : files.stat(fullFrom); - if (stats.isDirectory()) { - files.cp_r(fullFrom, fullTo, options); - } else if (stats.isSymbolicLink()) { - var linkText = files.readlink(fullFrom); - files.symlink(linkText, fullTo); - } else { - var absFullFrom = files.pathResolve(fullFrom); - - // Create the file as readable and writable by everyone, and executable by - // everyone if the original file is executably by owner. (This mode will - // be modified by umask.) We don't copy the mode *directly* because this - // function is used by 'meteor create' which is copying from the read-only - // tools tree into a writable app. - var mode = (stats.mode & 0o100) ? 0o777 : 0o666; - if (!options.transformContents) { - copyFileHelper(fullFrom, fullTo, mode); - } else { - var contents = files.readFile(fullFrom); - contents = options.transformContents(contents, f); - files.writeFile(fullTo, contents, { mode: mode }); + files.readdir(from).forEach(f => { + if (options.ignore && + _.any(options.ignore, + pattern => f.match(pattern))) { + return; } + + if (options.transformFilename) { + f = options.transformFilename(f); + } + + files.cp_r( + files.pathJoin(from, f), + files.pathJoin(to, f), + options + ); + }) + + } else if (stat.isSymbolicLink()) { + files.symlink(files.readlink(from), to); + + } else { + // Create the file as readable and writable by everyone, and + // executable by everyone if the original file is executable by + // owner. (This mode will be modified by umask.) We don't copy the + // mode *directly* because this function is used by 'meteor create' + // which is copying from the read-only tools tree into a writable app. + const mode = (stat.mode & 0o100) ? 0o777 : 0o666; + + if (options.transformContents) { + files.writeFile(to, options.transformContents( + files.readFile(from), + files.basename(from) + ), { mode }); + + } else { + copyFileHelper(from, to, mode); } - }); + } }; /** From 21462959f605af998cec441def60b07dcc4f483d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 16:26:34 -0400 Subject: [PATCH 110/688] Try to symlink rather than copying node_modules when rebuilding. --- tools/isobuild/meteor-npm.js | 89 ++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/tools/isobuild/meteor-npm.js b/tools/isobuild/meteor-npm.js index d8c9a21e32..8133506e46 100644 --- a/tools/isobuild/meteor-npm.js +++ b/tools/isobuild/meteor-npm.js @@ -270,9 +270,11 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { files.pathBasename(pkgPath) ); - // Copy instead of rename so that the original package directories - // will be left untouched if the rebuild fails. - files.cp_r(pkgPath, tempPkgDir); + // Copy the package directory instead of renaming it, so that the + // original package will be left untouched if the rebuild fails. We + // could just run files.cp_r(pkgPath, tempPkgDir) here, except that we + // want to handle nested node_modules directories specially. + copyNpmPackageWithSymlinkedNodeModules(pkgPath, tempPkgDir); // Record the current process.versions so that we can avoid // copying/rebuilding/renaming next time. @@ -291,6 +293,30 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { // If the `npm rebuild` command succeeded, overwrite the original // package directories with the rebuilt package directories. dirsToRebuild.forEach(function (pkgPath) { + const actualNodeModulesDir = + files.pathJoin(pkgPath, "node_modules"); + + const actualNodeModulesStat = + files.statOrNull(actualNodeModulesDir); + + if (actualNodeModulesStat && + actualNodeModulesStat.isDirectory()) { + // If the original package had a node_modules directory, move it + // into the temporary package directory, overwriting the one created + // by copyNpmPackageWithSymlinkedNodeModules (which contains only + // symlinks), so that when we rename the temporary directory back to + // the original directory below, we'll end up with a node_modules + // directory that contains real packages rather than symlinks. + + const symlinkNodeModulesDir = + files.pathJoin(tempPkgDirs[pkgPath], "node_modules"); + + files.renameDirAlmostAtomically( + actualNodeModulesDir, + symlinkNodeModulesDir + ); + } + files.renameDirAlmostAtomically(tempPkgDirs[pkgPath], pkgPath); }); @@ -299,6 +325,63 @@ Profile("meteorNpm.rebuildIfNonPortable", function (nodeModulesDir) { return true; }); +// Copy an npm package directory to another location, but attempt to +// symlink all of its node_modules rather than recursively copying them, +// which potentially saves a lot of time. +function copyNpmPackageWithSymlinkedNodeModules(fromPkgDir, toPkgDir) { + files.mkdir_p(toPkgDir); + + let needToHandleNodeModules = false; + + files.readdir(fromPkgDir).forEach(item => { + if (item === "node_modules") { + // We'll link or copy node_modules in a follow-up step. + needToHandleNodeModules = true; + return; + } + + files.cp_r( + files.pathJoin(fromPkgDir, item), + files.pathJoin(toPkgDir, item) + ); + }); + + if (! needToHandleNodeModules) { + return; + } + + const nodeModulesFromPath = files.pathJoin(fromPkgDir, "node_modules"); + const nodeModulesToPath = files.pathJoin(toPkgDir, "node_modules"); + + files.mkdir(nodeModulesToPath); + + files.readdir(nodeModulesFromPath).forEach(depPath => { + if (depPath === ".bin") { + // Avoid copying node_modules/.bin because commands like + // .bin/node-gyp and .bin/node-pre-gyp tend to cause problems. + return; + } + + const absDepFromPath = files.pathJoin(nodeModulesFromPath, depPath); + + if (! files.stat(absDepFromPath).isDirectory()) { + // Only copy package directories, even though there might be other + // kinds of files in node_modules. + return; + } + + const absDepToPath = files.pathJoin(nodeModulesToPath, depPath); + + // Try to symlink node_modules dependencies if possible (faster), + // and fall back to a recursive copy otherwise. + try { + files.symlink(absDepFromPath, absDepToPath, "junction"); + } catch (e) { + files.cp_r(absDepFromPath, absDepToPath); + } + }); +} + function isPortable(dir) { const lstat = files.lstat(dir); if (! lstat.isDirectory()) { From 31155ad990f3b6b834fef0138189e4af582a00a5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 17:27:48 -0400 Subject: [PATCH 111/688] Do not run `npm rebuild` for local node_modules directories. Since we do not write .meteor-last-rebuild-version.json files when developers run `meteor npm install ...`, this commit saves us from unnecessarily rebuilding any freshly-installed binary npm dependencies when Meteor starts. --- tools/isobuild/compiler.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/isobuild/compiler.js b/tools/isobuild/compiler.js index 1de3c021b0..a1d438b2dc 100644 --- a/tools/isobuild/compiler.js +++ b/tools/isobuild/compiler.js @@ -635,7 +635,16 @@ api.addAssets('${relPath}', 'client').`); if (! process.env.METEOR_FORCE_PORTABLE) { // Make sure we've rebuilt these npm packages according to the current // process.{platform,arch,versions}. - _.each(nodeModulesDirectories, nmd => nmd.rebuildIfNonPortable()); + _.each(nodeModulesDirectories, nmd => { + if (nmd.local) { + // Meteor never attempts to modify the contents of local + // node_modules directories (such as the one in the root directory + // of an application), so we call nmd.rebuildIfNonPortable() only + // when nmd.local is false. + } else { + nmd.rebuildIfNonPortable(); + } + }); if (process.env.METEOR_ALLOW_NON_PORTABLE || isopk.name === "meteor-tool") { From cc362a3bca9d0cf6a64f5fb4f691dbe1cdd8788a Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 18:33:10 -0400 Subject: [PATCH 112/688] Fix typo in new version of files.cp_r. --- tools/fs/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index d474c03a61..6e9ea93502 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -490,7 +490,7 @@ files.cp_r = function(from, to, options = {}) { if (options.transformContents) { files.writeFile(to, options.transformContents( files.readFile(from), - files.basename(from) + files.pathBasename(from) ), { mode }); } else { From 409f78b6689bb302cfeca7dcc3fa3b2b9e24bbc9 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 17:53:46 -0400 Subject: [PATCH 113/688] Bump package versions for 1.4.1-rc.5 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/babel-compiler/package.js | 2 +- packages/babel-runtime/package.js | 2 +- packages/caching-compiler/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ddp-client/package.js | 2 +- packages/ddp-server/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/email/package.js | 2 +- packages/es5-shim/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/http/package.js | 2 +- packages/jshint/package.js | 2 +- packages/less/package.js | 2 +- packages/logging/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/meteor/package.js | 2 +- packages/minifier-css/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/modules-runtime/package.js | 2 +- packages/modules/package.js | 2 +- packages/mongo/package.js | 2 +- packages/npm-bcrypt/package.js | 2 +- packages/npm-mongo/package.js | 2 +- packages/promise/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- packages/webapp/package.js | 2 +- packages/xmlbuilder/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 260a76316e..eeed4d714e 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.3" + version: "1.2.11-rc.5" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index b36d3d6cb1..3028405959 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.3" + version: "1.3.0-rc.5" }); Package.onUse(function(api) { diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 6075a69f37..1ede4ccb3a 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,7 +6,7 @@ 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.9.1-rc.3' + version: '6.9.1-rc.5' }); Npm.depends({ diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index 5a4bd373fd..90d6a23c43 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '0.1.11-rc.3', + version: '0.1.11-rc.5', documentation: 'README.md' }); diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 3c30b7709d..86137bf4db 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.7-rc.3', + version: '1.1.7-rc.5', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 2a8ff5b6b6..29881a1be5 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.3" + version: "1.2.4-rc.5" }); Package.registerBuildPlugin({ diff --git a/packages/ddp-client/package.js b/packages/ddp-client/package.js index cd4fdd4925..8c8bf8eef2 100644 --- a/packages/ddp-client/package.js +++ b/packages/ddp-client/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data client", - version: '1.3.1-rc.3', + version: '1.3.1-rc.5', documentation: null }); diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index 36121a3dbf..9808e712bd 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data server", - version: '1.3.10-rc.3', + version: '1.3.10-rc.5', documentation: null }); diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index eab3b6dd90..44b839fec9 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.3", + version: "0.3.14-rc.5", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 9d672879b1..8941f5d913 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.3', + version: '0.5.8-rc.5', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/email/package.js b/packages/email/package.js index 8fdce2fa5b..b3bcebfdac 100644 --- a/packages/email/package.js +++ b/packages/email/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Send email messages", - version: "1.1.17-rc.3" + version: "1.1.17-rc.5" }); Npm.depends({ diff --git a/packages/es5-shim/package.js b/packages/es5-shim/package.js index aead376fb7..cff0689b6f 100644 --- a/packages/es5-shim/package.js +++ b/packages/es5-shim/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "es5-shim", - version: "4.6.14-rc.3", + version: "4.6.14-rc.5", summary: "Shims and polyfills to improve ECMAScript 5 support", documentation: "README.md" }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 1a05254e7d..f4f93063d9 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.3" + version: "1.2.9-rc.5" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 31262757a4..5f505807f9 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.3" + version: "1.1.14-rc.5" }); Package.onUse(function(api) { diff --git a/packages/http/package.js b/packages/http/package.js index 4f62bfa2fb..70c84e1cc3 100644 --- a/packages/http/package.js +++ b/packages/http/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Make HTTP calls to remote servers", - version: '1.2.9-rc.3' + version: '1.2.9-rc.5' }); Npm.depends({ diff --git a/packages/jshint/package.js b/packages/jshint/package.js index 653b3ec043..6b28df1bb1 100644 --- a/packages/jshint/package.js +++ b/packages/jshint/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'jshint', - version: '1.1.6-rc.3', + version: '1.1.6-rc.5', summary: 'Lint all your JavaScript files with JSHint.', documentation: 'README.md' }); diff --git a/packages/less/package.js b/packages/less/package.js index fd76de85ce..12d9b0753e 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.3', + version: '2.7.5-rc.5', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/logging/package.js b/packages/logging/package.js index 0491a529b1..16f81a5cd3 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Logging facility.", - version: '1.1.15-rc.3' + version: '1.1.15-rc.5' }); Npm.depends({ diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 62c1db8d86..ee231d2fba 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.4.1-rc.3' + version: '1.4.1-rc.5' }); Package.includeTool(); diff --git a/packages/meteor/package.js b/packages/meteor/package.js index 70330120f3..688f02a073 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: "Core Meteor environment", - version: '1.2.17-rc.3' + version: '1.2.17-rc.5' }); Package.registerBuildPlugin({ diff --git a/packages/minifier-css/package.js b/packages/minifier-css/package.js index 58e08f06b2..0481abbd5d 100644 --- a/packages/minifier-css/package.js +++ b/packages/minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "CSS minifier", - version: "1.2.14-rc.3" + version: "1.2.14-rc.5" }); Npm.depends({ diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index c42ee5bbb7..cfcfa75974 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.3" + version: "1.2.14-rc.5" }); Npm.depends({ diff --git a/packages/modules-runtime/package.js b/packages/modules-runtime/package.js index f393599f80..2b1824993b 100644 --- a/packages/modules-runtime/package.js +++ b/packages/modules-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules-runtime", - version: "0.7.6-rc.3", + version: "0.7.6-rc.5", summary: "CommonJS module system", git: "https://github.com/benjamn/install", documentation: "README.md" diff --git a/packages/modules/package.js b/packages/modules/package.js index 2353d6d36b..8f50a1d283 100644 --- a/packages/modules/package.js +++ b/packages/modules/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules", - version: "0.7.6-rc.3", + version: "0.7.6-rc.5", summary: "CommonJS module system", documentation: "README.md" }); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index 9b6a93772b..91ca9be99c 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.11-rc.3' + version: '1.1.11-rc.5' }); Npm.depends({ diff --git a/packages/npm-bcrypt/package.js b/packages/npm-bcrypt/package.js index 7fdc4da1cb..be3bad1265 100644 --- a/packages/npm-bcrypt/package.js +++ b/packages/npm-bcrypt/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Wrapper around the bcrypt npm package", - version: "0.9.1-rc.3", + version: "0.9.1-rc.5", documentation: null }); diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 98ecf7261c..d8223dfb8d 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,7 +3,7 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.46-rc.3', + version: '1.5.46-rc.5', documentation: null }); diff --git a/packages/promise/package.js b/packages/promise/package.js index 3befaa2623..225bda7a51 100644 --- a/packages/promise/package.js +++ b/packages/promise/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "promise", - version: "0.8.4-rc.3", + version: "0.8.4-rc.5", summary: "ECMAScript 2015 Promise polyfill with Fiber support", git: "https://github.com/meteor/promise", documentation: "README.md" diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 3651d99c68..79a22b5f9d 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.3', + version: '1.2.0-rc.5', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 88d2fd0ba1..2c5b71918b 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.3', + version: '1.2.0-rc.5', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 5aa237b948..405e3da213 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.3', + version: '1.1.12-rc.5', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 349cf4ce10..72a2131b00 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.3" + version: "2.513.5-rc.5" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 12eeb9ff25..ffe3663538 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.3' + version: '1.2.14-rc.5' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 3e000291b2..5760d429e8 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.11-rc.3' + version: '1.3.11-rc.5' }); Npm.depends({connect: "2.30.2", diff --git a/packages/xmlbuilder/package.js b/packages/xmlbuilder/package.js index aa198437c8..4f75ec98bc 100644 --- a/packages/xmlbuilder/package.js +++ b/packages/xmlbuilder/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "An XML builder for node.js similar to java-xmlbuilder.", - version: '2.5.14-rc.3' + version: '2.5.14-rc.5' }); Npm.depends({ diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 0a88fb4b37..7fa9527140 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.3", + "version": "1.4.1-rc.5", "recommended": false, "official": false, "description": "Meteor" From 88bccdb36a04928cca0ae20e2ea97205229f0eaa Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Aug 2016 22:15:18 -0400 Subject: [PATCH 114/688] Tolerate missing source files in files.cp_r. --- tools/fs/files.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index 6e9ea93502..ae83d5e3ab 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -261,15 +261,21 @@ files.prettyPath = function (p) { // Like statSync, but null if file not found files.statOrNull = function (path) { + return statOrNull(path); +}; + +function statOrNull(path, preserveSymlinks) { try { - return files.stat(path); + return preserveSymlinks + ? files.lstat(path) + : files.stat(path); } catch (e) { - if (e.code == "ENOENT") { + if (e.code === "ENOENT") { return null; } throw e; } -}; +} // Like rm -r. files.rm_recursive = Profile("files.rm_recursive", function (p) { @@ -451,9 +457,10 @@ files.mkdir_p = function (dir, mode) { files.cp_r = function(from, to, options = {}) { from = files.pathResolve(from); - const stat = options.preserveSymlinks - ? files.lstat(from) - : files.stat(from); + const stat = statOrNull(from, options.preserveSymlinks); + if (! stat) { + return; + } if (stat.isDirectory()) { files.mkdir_p(to, 0o755); @@ -476,7 +483,12 @@ files.cp_r = function(from, to, options = {}) { ); }) - } else if (stat.isSymbolicLink()) { + return; + } + + files.mkdir_p(files.pathDirname(to)); + + if (stat.isSymbolicLink()) { files.symlink(files.readlink(from), to); } else { From 01e1dbf3521f6aee8e16decfd7b860e75bc01cb0 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 16 Aug 2016 17:20:27 +1000 Subject: [PATCH 115/688] Added `meteor update --all-packages` to update indirect dependencies See #7495. Still some decisions to be made: - Should we make --all-packages the default? - How should we deal with *new* indirect dependencies? - Should we do anything about underpinning indirect dependencies when updating? --- tools/cli/commands-packages.js | 28 ++++++++++--- .../.meteor/.gitignore | 1 + .../.meteor/.id | 7 ++++ .../.meteor/packages | 6 +++ .../.meteor/platforms | 2 + .../.meteor/release | 1 + .../.meteor/versions | 11 +++++ .../app-with-indirect-dependencies.js | 1 + tools/tests/update-tests.js | 40 +++++++++++++++++++ 9 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/.id create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/packages create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/release create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/versions create mode 100644 tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index a8574a8905..a1eb7abce8 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1546,7 +1546,8 @@ main.registerCommand({ options: { patch: { type: Boolean }, "packages-only": { type: Boolean }, - "allow-incompatible-update": { type: Boolean } + "allow-incompatible-update": { type: Boolean }, + "all-packages": { type: Boolean } }, // We have to be able to work without a release, since 'meteor // update' is how you fix apps that don't have a release. @@ -1611,13 +1612,28 @@ main.registerCommand({ // args), take patches to indirect dependencies. var upgradeIndirectDepPatchVersions = false; if (options.args.length === 0) { - projectContext.projectConstraintsFile.eachConstraint(function (constraint) { - if (! compiler.isIsobuildFeaturePackage(constraint.package)) { - upgradePackageNames.push(constraint.package); - } - }); + var allDependencies = _.keys(projectContext.packageMapFile._versions); + + // "all-packages" means update every package we depend on. The default + // is to tend to leave indirect dependencies (i.e. things not listed in + // `.meteor/packages`) alone. + if (options["all-packages"] && allDependencies.length > 0) { + upgradePackageNames = allDependencies; + } else { + projectContext.projectConstraintsFile.eachConstraint(function (constraint) { + if (! compiler.isIsobuildFeaturePackage(constraint.package)) { + upgradePackageNames.push(constraint.package); + } + }); + } upgradeIndirectDepPatchVersions = true; } else { + if (options["all-packages"]) { + Console.error("You cannot both specify a list of packages to" + + " update and pass --all-packages."); + exit(1) + } + upgradePackageNames = options.args; } diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/.id b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.id new file mode 100644 index 0000000000..a31494c6f4 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +1wehy3x1n3lcvy1v8vllm diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/packages b/tools/tests/apps/app-with-indirect-dependencies/.meteor/packages new file mode 100644 index 0000000000..3ccf15ba69 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/packages @@ -0,0 +1,6 @@ +# Meteor packages used by this project, one per line. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +tmeasday:direct-dependency@=1.0.0 diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms b/tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms new file mode 100644 index 0000000000..8a3a35f9f6 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms @@ -0,0 +1,2 @@ +browser +server diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/release b/tools/tests/apps/app-with-indirect-dependencies/.meteor/release new file mode 100644 index 0000000000..621e94f0ec --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/release @@ -0,0 +1 @@ +none diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/versions b/tools/tests/apps/app-with-indirect-dependencies/.meteor/versions new file mode 100644 index 0000000000..0a377b1bd8 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/versions @@ -0,0 +1,11 @@ +babel-compiler@6.9.0 +babel-runtime@0.1.10 +ecmascript@0.5.7 +ecmascript-runtime@0.3.13 +meteor@1.2.16 +modules@0.7.5 +modules-runtime@0.7.5 +promise@0.8.3 +tmeasday:direct-dependency@1.0.0 +tmeasday:indirect-dependency@1.0.0 +underscore@1.0.9 diff --git a/tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js b/tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js new file mode 100644 index 0000000000..0d201f4ca6 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js @@ -0,0 +1 @@ +// This app doesn't do anything, we just check versions diff --git a/tools/tests/update-tests.js b/tools/tests/update-tests.js index 97956b3df1..61d659e3ec 100644 --- a/tools/tests/update-tests.js +++ b/tools/tests/update-tests.js @@ -51,3 +51,43 @@ selftest.define("'meteor update' alters constraints in `.meteor/packages`", () = selftest.fail("Failed to update the version specifier for the `meteor-base` package"); } }); + +selftest.define("'meteor update' updates indirect dependencies with patches", () => { + const s = new Sandbox(); + + s.createApp("myapp", "app-with-indirect-dependencies", { + release: DEFAULT_RELEASE_TRACK + '@v1' + }); + s.cd("myapp"); + + var run = s.run("--prepare-app"); + // our .meteor/versions contains a version of this so we shouldn't change it + run.forbid(/indirect-dependency/); + run.expectExit(0); + + var update = s.run("update"); + // we have direct-dependency@=1.0.0, which depends on indirect@1.0.0 + // we should update to 1.0.1 (only take patches to indirect dependencies) + update.match(/indirect-dependency.*1.0.1/); + update.expectExit(0); +}); + +selftest.define("'meteor update --update-all' updates indirect dependencies to latest, within constraints", () => { + const s = new Sandbox(); + + s.createApp("myapp", "app-with-indirect-dependencies", { + release: DEFAULT_RELEASE_TRACK + '@v1' + }); + s.cd("myapp"); + + var run = s.run("--prepare-app"); + // our .meteor/versions contains a version of this so we shouldn't change it + run.forbid(/indirect-dependency/); + run.expectExit(0); + + var update = s.run("update", "--all-packages"); + // we have direct-dependency@=1.0.0, which depends on indirect@1.0.0 + // we should update to 1.1.0 but not 2.0.0 + update.match(/indirect-dependency.*1.1.0/); + update.expectExit(0); +}); From 1a8a1177e0040adc37d0a0f6515458550d533792 Mon Sep 17 00:00:00 2001 From: Yo-An Lin Date: Wed, 17 Aug 2016 22:00:15 +0800 Subject: [PATCH 116/688] Add option to skip release check (#7445) * Add --no-release-check option to skip release check * Add METEOR_NO_RELEASE_CHECK environment variable --- tools/cli/commands.js | 2 ++ tools/cli/help.txt | 1 + tools/runners/run-all.js | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 87473a5777..34cbe95e17 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -256,6 +256,7 @@ var runCommandOptions = { 'mobile-port': { type: String }, 'app-port': { type: String }, 'debug-port': { type: String }, + 'no-release-check': { type: Boolean }, production: { type: Boolean }, 'raw-logs': { type: Boolean }, settings: { type: String }, @@ -374,6 +375,7 @@ function doRunCommand(options) { oplogUrl: process.env.MONGO_OPLOG_URL, mobileServerUrl: utils.formatUrl(parsedMobileServerUrl), once: options.once, + noReleaseCheck: options['no-release-check'] || process.env.METEOR_NO_RELEASE_CHECK, cordovaRunner: cordovaRunner }); } diff --git a/tools/cli/help.txt b/tools/cli/help.txt index e8c942aa79..c402e8db51 100644 --- a/tools/cli/help.txt +++ b/tools/cli/help.txt @@ -58,6 +58,7 @@ Options: --release Specify the release of Meteor to use. --verbose Print all output from builds logs. --no-lint Don't run linters used by the app on every rebuild. + --no-release-check Don't run the release updater to check for new releases. --allow-incompatible-update Allow packages in your project to be upgraded or downgraded to versions that are potentially incompatible with the current versions, if required to satisfy all package diff --git a/tools/runners/run-all.js b/tools/runners/run-all.js index a49500a7f8..da225fe8c6 100644 --- a/tools/runners/run-all.js +++ b/tools/runners/run-all.js @@ -31,6 +31,7 @@ class Runner { rootUrl, selenium, seleniumBrowser, + noReleaseCheck, ...optionsForAppRunner }) { const self = this; @@ -46,6 +47,7 @@ class Runner { self.regenerateAppPort(); self.stopped = false; + self.noReleaseCheck = noReleaseCheck; self.quiet = quiet; self.banner = banner || files.convertToOSPath( files.prettyPath(self.projectContext.projectDir) @@ -125,7 +127,7 @@ class Runner { var unblockAppRunner = self.appRunner.makeBeforeStartPromise(); self._startMongoAsync().then(unblockAppRunner); - if (! self.stopped) { + if (!self.noReleaseCheck && ! self.stopped) { self.updater.start(); } From f006d98e8d89e8ecefce70ed25ea5ee37d8fc1c2 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 10:55:52 -0400 Subject: [PATCH 117/688] Filter --all-packages package names through isIsobuildFeaturePackage. --- tools/cli/commands-packages.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index a1eb7abce8..31d0f54c9b 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1612,21 +1612,26 @@ main.registerCommand({ // args), take patches to indirect dependencies. var upgradeIndirectDepPatchVersions = false; if (options.args.length === 0) { - var allDependencies = _.keys(projectContext.packageMapFile._versions); - // "all-packages" means update every package we depend on. The default // is to tend to leave indirect dependencies (i.e. things not listed in // `.meteor/packages`) alone. - if (options["all-packages"] && allDependencies.length > 0) { - upgradePackageNames = allDependencies; - } else { + if (options["all-packages"]) { + upgradePackageNames = _.filter( + _.keys(projectContext.packageMapFile.getCachedVersions()), + packageName => ! compiler.isIsobuildFeaturePackage(packageName) + ); + } + + if (upgradePackageNames.length === 0) { projectContext.projectConstraintsFile.eachConstraint(function (constraint) { if (! compiler.isIsobuildFeaturePackage(constraint.package)) { upgradePackageNames.push(constraint.package); } }); } + upgradeIndirectDepPatchVersions = true; + } else { if (options["all-packages"]) { Console.error("You cannot both specify a list of packages to" From 2d40f2c592f6314b8e3e6ac8c9f57e3b1600606a Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 10:56:25 -0400 Subject: [PATCH 118/688] Recommend `meteor update --all-packages` after partial update. --- tools/cli/commands-packages.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index 31d0f54c9b..36e0bff234 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1750,9 +1750,10 @@ main.registerCommand({ Console.info("\nNewer versions of the following indirect dependencies" + " are available:"); _.each(nonlatestIndirectDeps, printItem); - Console.info( - "To update one or more of these packages, pass their names to " + - "`meteor update`."); + Console.info([ + "To update one or more of these packages, pass their names to ", + "`meteor update`, or just run `meteor update --all-packages`." + ].join("\n")); } } }); From 2290911723ef19f56567afaafeab6424eef9893a Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 16 Aug 2016 17:20:27 +1000 Subject: [PATCH 119/688] Added `meteor update --all-packages` to update indirect dependencies See #7495. Still some decisions to be made: - Should we make --all-packages the default? - How should we deal with *new* indirect dependencies? - Should we do anything about underpinning indirect dependencies when updating? --- tools/cli/commands-packages.js | 28 ++++++++++--- .../.meteor/.gitignore | 1 + .../.meteor/.id | 7 ++++ .../.meteor/packages | 6 +++ .../.meteor/platforms | 2 + .../.meteor/release | 1 + .../.meteor/versions | 11 +++++ .../app-with-indirect-dependencies.js | 1 + tools/tests/update-tests.js | 40 +++++++++++++++++++ 9 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/.id create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/packages create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/release create mode 100644 tools/tests/apps/app-with-indirect-dependencies/.meteor/versions create mode 100644 tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index a8574a8905..a1eb7abce8 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1546,7 +1546,8 @@ main.registerCommand({ options: { patch: { type: Boolean }, "packages-only": { type: Boolean }, - "allow-incompatible-update": { type: Boolean } + "allow-incompatible-update": { type: Boolean }, + "all-packages": { type: Boolean } }, // We have to be able to work without a release, since 'meteor // update' is how you fix apps that don't have a release. @@ -1611,13 +1612,28 @@ main.registerCommand({ // args), take patches to indirect dependencies. var upgradeIndirectDepPatchVersions = false; if (options.args.length === 0) { - projectContext.projectConstraintsFile.eachConstraint(function (constraint) { - if (! compiler.isIsobuildFeaturePackage(constraint.package)) { - upgradePackageNames.push(constraint.package); - } - }); + var allDependencies = _.keys(projectContext.packageMapFile._versions); + + // "all-packages" means update every package we depend on. The default + // is to tend to leave indirect dependencies (i.e. things not listed in + // `.meteor/packages`) alone. + if (options["all-packages"] && allDependencies.length > 0) { + upgradePackageNames = allDependencies; + } else { + projectContext.projectConstraintsFile.eachConstraint(function (constraint) { + if (! compiler.isIsobuildFeaturePackage(constraint.package)) { + upgradePackageNames.push(constraint.package); + } + }); + } upgradeIndirectDepPatchVersions = true; } else { + if (options["all-packages"]) { + Console.error("You cannot both specify a list of packages to" + + " update and pass --all-packages."); + exit(1) + } + upgradePackageNames = options.args; } diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/.id b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.id new file mode 100644 index 0000000000..a31494c6f4 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +1wehy3x1n3lcvy1v8vllm diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/packages b/tools/tests/apps/app-with-indirect-dependencies/.meteor/packages new file mode 100644 index 0000000000..3ccf15ba69 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/packages @@ -0,0 +1,6 @@ +# Meteor packages used by this project, one per line. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +tmeasday:direct-dependency@=1.0.0 diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms b/tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms new file mode 100644 index 0000000000..8a3a35f9f6 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/platforms @@ -0,0 +1,2 @@ +browser +server diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/release b/tools/tests/apps/app-with-indirect-dependencies/.meteor/release new file mode 100644 index 0000000000..621e94f0ec --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/release @@ -0,0 +1 @@ +none diff --git a/tools/tests/apps/app-with-indirect-dependencies/.meteor/versions b/tools/tests/apps/app-with-indirect-dependencies/.meteor/versions new file mode 100644 index 0000000000..0a377b1bd8 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/.meteor/versions @@ -0,0 +1,11 @@ +babel-compiler@6.9.0 +babel-runtime@0.1.10 +ecmascript@0.5.7 +ecmascript-runtime@0.3.13 +meteor@1.2.16 +modules@0.7.5 +modules-runtime@0.7.5 +promise@0.8.3 +tmeasday:direct-dependency@1.0.0 +tmeasday:indirect-dependency@1.0.0 +underscore@1.0.9 diff --git a/tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js b/tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js new file mode 100644 index 0000000000..0d201f4ca6 --- /dev/null +++ b/tools/tests/apps/app-with-indirect-dependencies/app-with-indirect-dependencies.js @@ -0,0 +1 @@ +// This app doesn't do anything, we just check versions diff --git a/tools/tests/update-tests.js b/tools/tests/update-tests.js index 97956b3df1..61d659e3ec 100644 --- a/tools/tests/update-tests.js +++ b/tools/tests/update-tests.js @@ -51,3 +51,43 @@ selftest.define("'meteor update' alters constraints in `.meteor/packages`", () = selftest.fail("Failed to update the version specifier for the `meteor-base` package"); } }); + +selftest.define("'meteor update' updates indirect dependencies with patches", () => { + const s = new Sandbox(); + + s.createApp("myapp", "app-with-indirect-dependencies", { + release: DEFAULT_RELEASE_TRACK + '@v1' + }); + s.cd("myapp"); + + var run = s.run("--prepare-app"); + // our .meteor/versions contains a version of this so we shouldn't change it + run.forbid(/indirect-dependency/); + run.expectExit(0); + + var update = s.run("update"); + // we have direct-dependency@=1.0.0, which depends on indirect@1.0.0 + // we should update to 1.0.1 (only take patches to indirect dependencies) + update.match(/indirect-dependency.*1.0.1/); + update.expectExit(0); +}); + +selftest.define("'meteor update --update-all' updates indirect dependencies to latest, within constraints", () => { + const s = new Sandbox(); + + s.createApp("myapp", "app-with-indirect-dependencies", { + release: DEFAULT_RELEASE_TRACK + '@v1' + }); + s.cd("myapp"); + + var run = s.run("--prepare-app"); + // our .meteor/versions contains a version of this so we shouldn't change it + run.forbid(/indirect-dependency/); + run.expectExit(0); + + var update = s.run("update", "--all-packages"); + // we have direct-dependency@=1.0.0, which depends on indirect@1.0.0 + // we should update to 1.1.0 but not 2.0.0 + update.match(/indirect-dependency.*1.1.0/); + update.expectExit(0); +}); From e326fddafbcdf1073702ae0b112e76e77666c43e Mon Sep 17 00:00:00 2001 From: Yo-An Lin Date: Wed, 17 Aug 2016 22:00:15 +0800 Subject: [PATCH 120/688] Add option to skip release check (#7445) * Add --no-release-check option to skip release check * Add METEOR_NO_RELEASE_CHECK environment variable --- tools/cli/commands.js | 2 ++ tools/cli/help.txt | 1 + tools/runners/run-all.js | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 754e9b4535..6f75da283d 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -256,6 +256,7 @@ var runCommandOptions = { 'mobile-port': { type: String }, 'app-port': { type: String }, 'debug-port': { type: String }, + 'no-release-check': { type: Boolean }, production: { type: Boolean }, 'raw-logs': { type: Boolean }, settings: { type: String }, @@ -374,6 +375,7 @@ function doRunCommand(options) { oplogUrl: process.env.MONGO_OPLOG_URL, mobileServerUrl: utils.formatUrl(parsedMobileServerUrl), once: options.once, + noReleaseCheck: options['no-release-check'] || process.env.METEOR_NO_RELEASE_CHECK, cordovaRunner: cordovaRunner }); } diff --git a/tools/cli/help.txt b/tools/cli/help.txt index e8c942aa79..c402e8db51 100644 --- a/tools/cli/help.txt +++ b/tools/cli/help.txt @@ -58,6 +58,7 @@ Options: --release Specify the release of Meteor to use. --verbose Print all output from builds logs. --no-lint Don't run linters used by the app on every rebuild. + --no-release-check Don't run the release updater to check for new releases. --allow-incompatible-update Allow packages in your project to be upgraded or downgraded to versions that are potentially incompatible with the current versions, if required to satisfy all package diff --git a/tools/runners/run-all.js b/tools/runners/run-all.js index a49500a7f8..da225fe8c6 100644 --- a/tools/runners/run-all.js +++ b/tools/runners/run-all.js @@ -31,6 +31,7 @@ class Runner { rootUrl, selenium, seleniumBrowser, + noReleaseCheck, ...optionsForAppRunner }) { const self = this; @@ -46,6 +47,7 @@ class Runner { self.regenerateAppPort(); self.stopped = false; + self.noReleaseCheck = noReleaseCheck; self.quiet = quiet; self.banner = banner || files.convertToOSPath( files.prettyPath(self.projectContext.projectDir) @@ -125,7 +127,7 @@ class Runner { var unblockAppRunner = self.appRunner.makeBeforeStartPromise(); self._startMongoAsync().then(unblockAppRunner); - if (! self.stopped) { + if (!self.noReleaseCheck && ! self.stopped) { self.updater.start(); } From 9249985875d68e5150e844758e9842f6f8260b11 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 10:55:52 -0400 Subject: [PATCH 121/688] Filter --all-packages package names through isIsobuildFeaturePackage. --- tools/cli/commands-packages.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index a1eb7abce8..31d0f54c9b 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1612,21 +1612,26 @@ main.registerCommand({ // args), take patches to indirect dependencies. var upgradeIndirectDepPatchVersions = false; if (options.args.length === 0) { - var allDependencies = _.keys(projectContext.packageMapFile._versions); - // "all-packages" means update every package we depend on. The default // is to tend to leave indirect dependencies (i.e. things not listed in // `.meteor/packages`) alone. - if (options["all-packages"] && allDependencies.length > 0) { - upgradePackageNames = allDependencies; - } else { + if (options["all-packages"]) { + upgradePackageNames = _.filter( + _.keys(projectContext.packageMapFile.getCachedVersions()), + packageName => ! compiler.isIsobuildFeaturePackage(packageName) + ); + } + + if (upgradePackageNames.length === 0) { projectContext.projectConstraintsFile.eachConstraint(function (constraint) { if (! compiler.isIsobuildFeaturePackage(constraint.package)) { upgradePackageNames.push(constraint.package); } }); } + upgradeIndirectDepPatchVersions = true; + } else { if (options["all-packages"]) { Console.error("You cannot both specify a list of packages to" From d6ffff50b5cff243ce22d30874bd14dc9073df82 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 10:56:25 -0400 Subject: [PATCH 122/688] Recommend `meteor update --all-packages` after partial update. --- tools/cli/commands-packages.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/cli/commands-packages.js b/tools/cli/commands-packages.js index 31d0f54c9b..36e0bff234 100644 --- a/tools/cli/commands-packages.js +++ b/tools/cli/commands-packages.js @@ -1750,9 +1750,10 @@ main.registerCommand({ Console.info("\nNewer versions of the following indirect dependencies" + " are available:"); _.each(nonlatestIndirectDeps, printItem); - Console.info( - "To update one or more of these packages, pass their names to " + - "`meteor update`."); + Console.info([ + "To update one or more of these packages, pass their names to ", + "`meteor update`, or just run `meteor update --all-packages`." + ].join("\n")); } } }); From 61012963a5fc1e18ae8da65c8e5e9683ef231b2f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 14:52:50 -0400 Subject: [PATCH 123/688] Fix test description to say --all-packages instead of --update-all. --- tools/tests/update-tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tests/update-tests.js b/tools/tests/update-tests.js index 61d659e3ec..035246d3d9 100644 --- a/tools/tests/update-tests.js +++ b/tools/tests/update-tests.js @@ -72,7 +72,7 @@ selftest.define("'meteor update' updates indirect dependencies with patches", () update.expectExit(0); }); -selftest.define("'meteor update --update-all' updates indirect dependencies to latest, within constraints", () => { +selftest.define("'meteor update --all-packages' updates indirect dependencies to latest, within constraints", () => { const s = new Sandbox(); s.createApp("myapp", "app-with-indirect-dependencies", { From c51ca7357534c7c649540d395ab71aea9e2f098b Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 09:58:40 -0400 Subject: [PATCH 124/688] Bump package versions for 1.4.1-rc.6 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/babel-compiler/package.js | 2 +- packages/babel-runtime/package.js | 2 +- packages/caching-compiler/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ddp-client/package.js | 2 +- packages/ddp-server/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/email/package.js | 2 +- packages/es5-shim/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/http/package.js | 2 +- packages/jshint/package.js | 2 +- packages/less/package.js | 2 +- packages/logging/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/meteor/package.js | 2 +- packages/minifier-css/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/modules-runtime/package.js | 2 +- packages/modules/package.js | 2 +- packages/mongo/package.js | 2 +- packages/npm-bcrypt/package.js | 2 +- packages/npm-mongo/package.js | 2 +- packages/promise/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- packages/webapp/package.js | 2 +- packages/xmlbuilder/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index eeed4d714e..1b48bc7bbb 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.5" + version: "1.2.11-rc.6" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 3028405959..67b7405955 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.5" + version: "1.3.0-rc.6" }); Package.onUse(function(api) { diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 1ede4ccb3a..568d55803b 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,7 +6,7 @@ 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.9.1-rc.5' + version: '6.9.1-rc.6' }); Npm.depends({ diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index 90d6a23c43..11a9e16f72 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '0.1.11-rc.5', + version: '0.1.11-rc.6', documentation: 'README.md' }); diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 86137bf4db..7d3ad3f0b8 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.7-rc.5', + version: '1.1.7-rc.6', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 29881a1be5..a5d7e230c4 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.5" + version: "1.2.4-rc.6" }); Package.registerBuildPlugin({ diff --git a/packages/ddp-client/package.js b/packages/ddp-client/package.js index 8c8bf8eef2..00575e5e36 100644 --- a/packages/ddp-client/package.js +++ b/packages/ddp-client/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data client", - version: '1.3.1-rc.5', + version: '1.3.1-rc.6', documentation: null }); diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index 9808e712bd..edfa6eaa4a 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data server", - version: '1.3.10-rc.5', + version: '1.3.10-rc.6', documentation: null }); diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index 44b839fec9..f5ce59c10e 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.5", + version: "0.3.14-rc.6", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 8941f5d913..05dc6b1909 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.5', + version: '0.5.8-rc.6', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/email/package.js b/packages/email/package.js index b3bcebfdac..47164f4ea2 100644 --- a/packages/email/package.js +++ b/packages/email/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Send email messages", - version: "1.1.17-rc.5" + version: "1.1.17-rc.6" }); Npm.depends({ diff --git a/packages/es5-shim/package.js b/packages/es5-shim/package.js index cff0689b6f..151cb4eec2 100644 --- a/packages/es5-shim/package.js +++ b/packages/es5-shim/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "es5-shim", - version: "4.6.14-rc.5", + version: "4.6.14-rc.6", summary: "Shims and polyfills to improve ECMAScript 5 support", documentation: "README.md" }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index f4f93063d9..c401f26b51 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.5" + version: "1.2.9-rc.6" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 5f505807f9..59b7372a05 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.5" + version: "1.1.14-rc.6" }); Package.onUse(function(api) { diff --git a/packages/http/package.js b/packages/http/package.js index 70c84e1cc3..82cd28f99f 100644 --- a/packages/http/package.js +++ b/packages/http/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Make HTTP calls to remote servers", - version: '1.2.9-rc.5' + version: '1.2.9-rc.6' }); Npm.depends({ diff --git a/packages/jshint/package.js b/packages/jshint/package.js index 6b28df1bb1..bfd19e8e10 100644 --- a/packages/jshint/package.js +++ b/packages/jshint/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'jshint', - version: '1.1.6-rc.5', + version: '1.1.6-rc.6', summary: 'Lint all your JavaScript files with JSHint.', documentation: 'README.md' }); diff --git a/packages/less/package.js b/packages/less/package.js index 12d9b0753e..dd3b65eb3b 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.5', + version: '2.7.5-rc.6', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/logging/package.js b/packages/logging/package.js index 16f81a5cd3..721e4a5f9d 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Logging facility.", - version: '1.1.15-rc.5' + version: '1.1.15-rc.6' }); Npm.depends({ diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index ee231d2fba..fe40e962b6 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.4.1-rc.5' + version: '1.4.1-rc.6' }); Package.includeTool(); diff --git a/packages/meteor/package.js b/packages/meteor/package.js index 688f02a073..2db233f6da 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: "Core Meteor environment", - version: '1.2.17-rc.5' + version: '1.2.17-rc.6' }); Package.registerBuildPlugin({ diff --git a/packages/minifier-css/package.js b/packages/minifier-css/package.js index 0481abbd5d..8a1bef2907 100644 --- a/packages/minifier-css/package.js +++ b/packages/minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "CSS minifier", - version: "1.2.14-rc.5" + version: "1.2.14-rc.6" }); Npm.depends({ diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index cfcfa75974..c43bb4234f 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.5" + version: "1.2.14-rc.6" }); Npm.depends({ diff --git a/packages/modules-runtime/package.js b/packages/modules-runtime/package.js index 2b1824993b..3542682a39 100644 --- a/packages/modules-runtime/package.js +++ b/packages/modules-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules-runtime", - version: "0.7.6-rc.5", + version: "0.7.6-rc.6", summary: "CommonJS module system", git: "https://github.com/benjamn/install", documentation: "README.md" diff --git a/packages/modules/package.js b/packages/modules/package.js index 8f50a1d283..750af4415f 100644 --- a/packages/modules/package.js +++ b/packages/modules/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules", - version: "0.7.6-rc.5", + version: "0.7.6-rc.6", summary: "CommonJS module system", documentation: "README.md" }); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index 91ca9be99c..7f3d262c25 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.11-rc.5' + version: '1.1.11-rc.6' }); Npm.depends({ diff --git a/packages/npm-bcrypt/package.js b/packages/npm-bcrypt/package.js index be3bad1265..31725db763 100644 --- a/packages/npm-bcrypt/package.js +++ b/packages/npm-bcrypt/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Wrapper around the bcrypt npm package", - version: "0.9.1-rc.5", + version: "0.9.1-rc.6", documentation: null }); diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index d8223dfb8d..5321034eea 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,7 +3,7 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.46-rc.5', + version: '1.5.46-rc.6', documentation: null }); diff --git a/packages/promise/package.js b/packages/promise/package.js index 225bda7a51..7f64070b24 100644 --- a/packages/promise/package.js +++ b/packages/promise/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "promise", - version: "0.8.4-rc.5", + version: "0.8.4-rc.6", summary: "ECMAScript 2015 Promise polyfill with Fiber support", git: "https://github.com/meteor/promise", documentation: "README.md" diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 79a22b5f9d..98544f24c2 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.5', + version: '1.2.0-rc.6', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 2c5b71918b..f71e5bcfee 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.5', + version: '1.2.0-rc.6', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 405e3da213..f1eabeebc3 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.5', + version: '1.1.12-rc.6', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 72a2131b00..618d4e8f53 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.5" + version: "2.513.5-rc.6" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index ffe3663538..0f48bee0c2 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.5' + version: '1.2.14-rc.6' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 5760d429e8..58087d117a 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.11-rc.5' + version: '1.3.11-rc.6' }); Npm.depends({connect: "2.30.2", diff --git a/packages/xmlbuilder/package.js b/packages/xmlbuilder/package.js index 4f75ec98bc..3e3936c6b1 100644 --- a/packages/xmlbuilder/package.js +++ b/packages/xmlbuilder/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "An XML builder for node.js similar to java-xmlbuilder.", - version: '2.5.14-rc.5' + version: '2.5.14-rc.6' }); Npm.depends({ diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 7fa9527140..ef69a3f764 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.5", + "version": "1.4.1-rc.6", "recommended": false, "official": false, "description": "Meteor" From ff0f9fe7b64bb0aec39123d64758f2cb704fc4eb Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 15:27:15 -0400 Subject: [PATCH 125/688] Update History.md with recent changes in 1.4.1. --- History.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/History.md b/History.md index 5ce9cff087..d2041e0c95 100644 --- a/History.md +++ b/History.md @@ -105,6 +105,16 @@ deployed apps has been fixed. [#7609](https://github.com/meteor/meteor/pull/7609). +* The `meteor update` command now supports an `--all-packages` flag to + update all packages (including indirect dependencies) to their latest + compatible versions, similar to passing the names of all your packages + to the `meteor update` command. + [#7653](https://github.com/meteor/meteor/pull/7653) + +* Background release updates can now be disabled by invoking either + `meteor --no-release-check` or `METEOR_NO_RELEASE_CHECK=1 meteor`. + [#7445](https://github.com/meteor/meteor/pull/7445) + ## v1.4.0.1 * Fix issue with the 1.4 tool springboarding to older releases (see [Issue #7491](https://github.com/meteor/meteor/issues/7491)) From 61c1ab0cac9f437f7472d526cf391ea565c9a0bb Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 18:08:24 -0400 Subject: [PATCH 126/688] Avoid colons in .npm/plugin/... paths. Fixes #7661. --- tools/isobuild/compiler.js | 6 ++++-- tools/isobuild/meteor-npm.js | 6 +++++- tools/isobuild/package-source.js | 6 +++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/isobuild/compiler.js b/tools/isobuild/compiler.js index a1d438b2dc..ba0146d921 100644 --- a/tools/isobuild/compiler.js +++ b/tools/isobuild/compiler.js @@ -73,8 +73,10 @@ compiler.compile = Profile(function (packageSource, options) { // Plugins have their own npm dependencies separate from the // rest of the package, so they need their own separate npm // shrinkwrap and cache state. - npmDir: files.pathResolve( - files.pathJoin(packageSource.sourceRoot, '.npm', 'plugin', info.name)) + npmDir: files.pathResolve(files.pathJoin( + packageSource.sourceRoot, + '.npm', 'plugin', colonConverter.convert(info.name) + )) }); // Add this plugin's dependencies to our "plugin dependency" // WatchSet. buildResult.watchSet will end up being the merged diff --git a/tools/isobuild/meteor-npm.js b/tools/isobuild/meteor-npm.js index 8133506e46..5416617b34 100644 --- a/tools/isobuild/meteor-npm.js +++ b/tools/isobuild/meteor-npm.js @@ -18,6 +18,9 @@ import { execFileAsync } from "../utils/processes.js"; import { get as getRebuildArgs } from "../static-assets/server/npm-rebuild-args.js"; +import { + convert as convertColonsInPath +} from "../utils/colon-converter.js"; var meteorNpm = exports; @@ -52,7 +55,8 @@ meteorNpm.updateDependencies = function (packageName, // we can then atomically rename it. we also make sure to // randomize the name, in case we're bundling this package // multiple times in parallel. - var newPackageNpmDir = packageNpmDir + '-new-' + utils.randomToken(); + var newPackageNpmDir = + convertColonsInPath(packageNpmDir) + '-new-' + utils.randomToken(); if (! npmDependencies || _.isEmpty(npmDependencies)) { // No NPM dependencies? Delete the .npm directory if it exists (because, diff --git a/tools/isobuild/package-source.js b/tools/isobuild/package-source.js index 39648e1667..e0a5acedc9 100644 --- a/tools/isobuild/package-source.js +++ b/tools/isobuild/package-source.js @@ -22,6 +22,10 @@ import { APP_TEST_FILENAME_REGEXPS, isTestFilePath } from './test-files.js'; +import { + convert as convertColonsInPath +} from '../utils/colon-converter.js'; + // XXX: This is a medium-term hack, to avoid having the user set a package name // & test-name in package.describe. We will change this in the new control file // world in some way. @@ -386,7 +390,7 @@ _.extend(PackageSource.prototype, { utils.ensureOnlyValidVersions(options.npmDependencies, {forCordova: false}); self.npmDependencies = options.npmDependencies; - self.npmCacheDirectory = options.npmDir; + self.npmCacheDirectory = convertColonsInPath(options.npmDir); utils.ensureOnlyValidVersions(options.cordovaDependencies, {forCordova: true}); self.cordovaDependencies = options.cordovaDependencies; From 4c1fe8ff2205922e0659a69b81cb5c5ddd139fe2 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 18:14:15 -0400 Subject: [PATCH 127/688] Convert options.npmDir only if it's a string. --- tools/isobuild/package-source.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/isobuild/package-source.js b/tools/isobuild/package-source.js index e0a5acedc9..2b2636967a 100644 --- a/tools/isobuild/package-source.js +++ b/tools/isobuild/package-source.js @@ -390,7 +390,11 @@ _.extend(PackageSource.prototype, { utils.ensureOnlyValidVersions(options.npmDependencies, {forCordova: false}); self.npmDependencies = options.npmDependencies; - self.npmCacheDirectory = convertColonsInPath(options.npmDir); + + // If options.npmDir is a string, make sure it contains no colons. + self.npmCacheDirectory = _.isString(options.npmDir) + ? convertColonsInPath(options.npmDir) + : options.npmDir; utils.ensureOnlyValidVersions(options.cordovaDependencies, {forCordova: true}); self.cordovaDependencies = options.cordovaDependencies; From e90c638c9fbc34f0047c1db972e15ef33be0b979 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 17 Aug 2016 18:12:07 -0400 Subject: [PATCH 128/688] Bump package versions for 1.4.1-rc.7 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/babel-compiler/package.js | 2 +- packages/babel-runtime/package.js | 2 +- packages/caching-compiler/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ddp-client/package.js | 2 +- packages/ddp-server/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/email/package.js | 2 +- packages/es5-shim/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/http/package.js | 2 +- packages/jshint/package.js | 2 +- packages/less/package.js | 2 +- packages/logging/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/meteor/package.js | 2 +- packages/minifier-css/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/modules-runtime/package.js | 2 +- packages/modules/package.js | 2 +- packages/mongo/package.js | 2 +- packages/npm-bcrypt/package.js | 2 +- packages/npm-mongo/package.js | 2 +- packages/promise/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- packages/webapp/package.js | 2 +- packages/xmlbuilder/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 1b48bc7bbb..3030aaefe1 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.6" + version: "1.2.11-rc.7" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 67b7405955..38a3cb19e9 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.6" + version: "1.3.0-rc.7" }); Package.onUse(function(api) { diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 568d55803b..56a4dd4da6 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,7 +6,7 @@ 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.9.1-rc.6' + version: '6.9.1-rc.7' }); Npm.depends({ diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index 11a9e16f72..ad4f40b07d 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '0.1.11-rc.6', + version: '0.1.11-rc.7', documentation: 'README.md' }); diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 7d3ad3f0b8..515eaf513a 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.7-rc.6', + version: '1.1.7-rc.7', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index a5d7e230c4..2b1b2c5531 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.6" + version: "1.2.4-rc.7" }); Package.registerBuildPlugin({ diff --git a/packages/ddp-client/package.js b/packages/ddp-client/package.js index 00575e5e36..91855ac460 100644 --- a/packages/ddp-client/package.js +++ b/packages/ddp-client/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data client", - version: '1.3.1-rc.6', + version: '1.3.1-rc.7', documentation: null }); diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index edfa6eaa4a..e68798c23b 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data server", - version: '1.3.10-rc.6', + version: '1.3.10-rc.7', documentation: null }); diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index f5ce59c10e..4c79fa357f 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.6", + version: "0.3.14-rc.7", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 05dc6b1909..836bef7d8e 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.6', + version: '0.5.8-rc.7', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/email/package.js b/packages/email/package.js index 47164f4ea2..59c72289fa 100644 --- a/packages/email/package.js +++ b/packages/email/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Send email messages", - version: "1.1.17-rc.6" + version: "1.1.17-rc.7" }); Npm.depends({ diff --git a/packages/es5-shim/package.js b/packages/es5-shim/package.js index 151cb4eec2..285c1abf75 100644 --- a/packages/es5-shim/package.js +++ b/packages/es5-shim/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "es5-shim", - version: "4.6.14-rc.6", + version: "4.6.14-rc.7", summary: "Shims and polyfills to improve ECMAScript 5 support", documentation: "README.md" }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index c401f26b51..35ca86ce7f 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.6" + version: "1.2.9-rc.7" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 59b7372a05..69784f1662 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.6" + version: "1.1.14-rc.7" }); Package.onUse(function(api) { diff --git a/packages/http/package.js b/packages/http/package.js index 82cd28f99f..70b2b8a03a 100644 --- a/packages/http/package.js +++ b/packages/http/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Make HTTP calls to remote servers", - version: '1.2.9-rc.6' + version: '1.2.9-rc.7' }); Npm.depends({ diff --git a/packages/jshint/package.js b/packages/jshint/package.js index bfd19e8e10..1c7a749a98 100644 --- a/packages/jshint/package.js +++ b/packages/jshint/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'jshint', - version: '1.1.6-rc.6', + version: '1.1.6-rc.7', summary: 'Lint all your JavaScript files with JSHint.', documentation: 'README.md' }); diff --git a/packages/less/package.js b/packages/less/package.js index dd3b65eb3b..9f2c3db570 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.6', + version: '2.7.5-rc.7', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/logging/package.js b/packages/logging/package.js index 721e4a5f9d..3a4cd431a3 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Logging facility.", - version: '1.1.15-rc.6' + version: '1.1.15-rc.7' }); Npm.depends({ diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index fe40e962b6..84dc134625 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.4.1-rc.6' + version: '1.4.1-rc.7' }); Package.includeTool(); diff --git a/packages/meteor/package.js b/packages/meteor/package.js index 2db233f6da..2ca6ed9ea7 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: "Core Meteor environment", - version: '1.2.17-rc.6' + version: '1.2.17-rc.7' }); Package.registerBuildPlugin({ diff --git a/packages/minifier-css/package.js b/packages/minifier-css/package.js index 8a1bef2907..d245e4a1f0 100644 --- a/packages/minifier-css/package.js +++ b/packages/minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "CSS minifier", - version: "1.2.14-rc.6" + version: "1.2.14-rc.7" }); Npm.depends({ diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index c43bb4234f..9931ae310f 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.6" + version: "1.2.14-rc.7" }); Npm.depends({ diff --git a/packages/modules-runtime/package.js b/packages/modules-runtime/package.js index 3542682a39..29e38fbdf9 100644 --- a/packages/modules-runtime/package.js +++ b/packages/modules-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules-runtime", - version: "0.7.6-rc.6", + version: "0.7.6-rc.7", summary: "CommonJS module system", git: "https://github.com/benjamn/install", documentation: "README.md" diff --git a/packages/modules/package.js b/packages/modules/package.js index 750af4415f..8502eb2998 100644 --- a/packages/modules/package.js +++ b/packages/modules/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules", - version: "0.7.6-rc.6", + version: "0.7.6-rc.7", summary: "CommonJS module system", documentation: "README.md" }); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index 7f3d262c25..efe8333db8 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.11-rc.6' + version: '1.1.11-rc.7' }); Npm.depends({ diff --git a/packages/npm-bcrypt/package.js b/packages/npm-bcrypt/package.js index 31725db763..bd4691739b 100644 --- a/packages/npm-bcrypt/package.js +++ b/packages/npm-bcrypt/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Wrapper around the bcrypt npm package", - version: "0.9.1-rc.6", + version: "0.9.1-rc.7", documentation: null }); diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 5321034eea..1736f93022 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,7 +3,7 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.46-rc.6', + version: '1.5.46-rc.7', documentation: null }); diff --git a/packages/promise/package.js b/packages/promise/package.js index 7f64070b24..d5682f810e 100644 --- a/packages/promise/package.js +++ b/packages/promise/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "promise", - version: "0.8.4-rc.6", + version: "0.8.4-rc.7", summary: "ECMAScript 2015 Promise polyfill with Fiber support", git: "https://github.com/meteor/promise", documentation: "README.md" diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index 98544f24c2..d943a4121e 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.6', + version: '1.2.0-rc.7', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index f71e5bcfee..08545f5b0b 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.6', + version: '1.2.0-rc.7', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index f1eabeebc3..793ee538ec 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.6', + version: '1.1.12-rc.7', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 618d4e8f53..876fe279a5 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.6" + version: "2.513.5-rc.7" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 0f48bee0c2..8688fbc23f 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.6' + version: '1.2.14-rc.7' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 58087d117a..eab6166de2 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.11-rc.6' + version: '1.3.11-rc.7' }); Npm.depends({connect: "2.30.2", diff --git a/packages/xmlbuilder/package.js b/packages/xmlbuilder/package.js index 3e3936c6b1..c075642bed 100644 --- a/packages/xmlbuilder/package.js +++ b/packages/xmlbuilder/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "An XML builder for node.js similar to java-xmlbuilder.", - version: '2.5.14-rc.6' + version: '2.5.14-rc.7' }); Npm.depends({ diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index ef69a3f764..2a7ca869b9 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.6", + "version": "1.4.1-rc.7", "recommended": false, "official": false, "description": "Meteor" From 365c765971a9f0a0bcf816ec76badcff7ca025a5 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 18 Aug 2016 11:37:18 -0400 Subject: [PATCH 129/688] Bump package versions for the official 1.4.1 release. --- packages/accounts-base/package.js | 2 +- packages/accounts-password/package.js | 2 +- packages/babel-compiler/package.js | 2 +- packages/babel-runtime/package.js | 2 +- packages/caching-compiler/package.js | 2 +- packages/coffeescript/package.js | 2 +- packages/ddp-client/package.js | 2 +- packages/ddp-server/package.js | 2 +- packages/ecmascript-runtime/package.js | 2 +- packages/ecmascript/package.js | 2 +- packages/email/package.js | 2 +- packages/es5-shim/package.js | 2 +- packages/facebook/package.js | 2 +- packages/google/package.js | 2 +- packages/http/package.js | 2 +- packages/jshint/package.js | 2 +- packages/less/package.js | 2 +- packages/logging/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/meteor/package.js | 2 +- packages/minifier-css/package.js | 2 +- packages/minifier-js/package.js | 2 +- packages/modules-runtime/package.js | 2 +- packages/modules/package.js | 2 +- packages/mongo/package.js | 2 +- packages/npm-bcrypt/package.js | 2 +- packages/npm-mongo/package.js | 2 +- packages/promise/package.js | 2 +- packages/standard-minifier-css/package.js | 2 +- packages/standard-minifier-js/package.js | 2 +- packages/static-html/package.js | 2 +- packages/stylus/package.js | 2 +- packages/templating/package.js | 2 +- packages/webapp/package.js | 2 +- packages/xmlbuilder/package.js | 2 +- scripts/admin/meteor-release-official.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 3030aaefe1..e162820f3e 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.2.11-rc.7" + version: "1.2.11" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 38a3cb19e9..6e1e8e9dcb 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.0-rc.7" + version: "1.3.0" }); Package.onUse(function(api) { diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 56a4dd4da6..94daa41410 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,7 +6,7 @@ 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.9.1-rc.7' + version: '6.9.1' }); Npm.depends({ diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index ad4f40b07d..a3a2050c94 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '0.1.11-rc.7', + version: '0.1.11', documentation: 'README.md' }); diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 515eaf513a..f9c2ac587b 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.7-rc.7', + version: '1.1.7', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index 2b1b2c5531..e3cc7cdcaa 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4-rc.7" + version: "1.2.4" }); Package.registerBuildPlugin({ diff --git a/packages/ddp-client/package.js b/packages/ddp-client/package.js index 91855ac460..d49ca97779 100644 --- a/packages/ddp-client/package.js +++ b/packages/ddp-client/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data client", - version: '1.3.1-rc.7', + version: '1.3.1', documentation: null }); diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index e68798c23b..e3c599d45d 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data server", - version: '1.3.10-rc.7', + version: '1.3.10', documentation: null }); diff --git a/packages/ecmascript-runtime/package.js b/packages/ecmascript-runtime/package.js index 4c79fa357f..0174dcc23a 100644 --- a/packages/ecmascript-runtime/package.js +++ b/packages/ecmascript-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "ecmascript-runtime", - version: "0.3.14-rc.7", + version: "0.3.14", summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set", git: "https://github.com/meteor/ecmascript-runtime", documentation: "README.md" diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 836bef7d8e..7643da24c9 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.8-rc.7', + version: '0.5.8', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/email/package.js b/packages/email/package.js index 59c72289fa..bb30e9853e 100644 --- a/packages/email/package.js +++ b/packages/email/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Send email messages", - version: "1.1.17-rc.7" + version: "1.1.17" }); Npm.depends({ diff --git a/packages/es5-shim/package.js b/packages/es5-shim/package.js index 285c1abf75..c7dcc696ab 100644 --- a/packages/es5-shim/package.js +++ b/packages/es5-shim/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "es5-shim", - version: "4.6.14-rc.7", + version: "4.6.14", summary: "Shims and polyfills to improve ECMAScript 5 support", documentation: "README.md" }); diff --git a/packages/facebook/package.js b/packages/facebook/package.js index 35ca86ce7f..f7883bb59e 100644 --- a/packages/facebook/package.js +++ b/packages/facebook/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Facebook OAuth flow", - version: "1.2.9-rc.7" + version: "1.2.9" }); Package.onUse(function(api) { diff --git a/packages/google/package.js b/packages/google/package.js index 69784f1662..9ecc80a3c4 100644 --- a/packages/google/package.js +++ b/packages/google/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Google OAuth flow", - version: "1.1.14-rc.7" + version: "1.1.14" }); Package.onUse(function(api) { diff --git a/packages/http/package.js b/packages/http/package.js index 70b2b8a03a..dd130ccb72 100644 --- a/packages/http/package.js +++ b/packages/http/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Make HTTP calls to remote servers", - version: '1.2.9-rc.7' + version: '1.2.9' }); Npm.depends({ diff --git a/packages/jshint/package.js b/packages/jshint/package.js index 1c7a749a98..6527945fd5 100644 --- a/packages/jshint/package.js +++ b/packages/jshint/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'jshint', - version: '1.1.6-rc.7', + version: '1.1.6', summary: 'Lint all your JavaScript files with JSHint.', documentation: 'README.md' }); diff --git a/packages/less/package.js b/packages/less/package.js index 9f2c3db570..ac0a88c577 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.5-rc.7', + version: '2.7.5', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/logging/package.js b/packages/logging/package.js index 3a4cd431a3..567aa4d3a6 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Logging facility.", - version: '1.1.15-rc.7' + version: '1.1.15' }); Npm.depends({ diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 84dc134625..901bfc0808 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.4.1-rc.7' + version: '1.4.1' }); Package.includeTool(); diff --git a/packages/meteor/package.js b/packages/meteor/package.js index 2ca6ed9ea7..2941f35c7c 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: "Core Meteor environment", - version: '1.2.17-rc.7' + version: '1.2.17' }); Package.registerBuildPlugin({ diff --git a/packages/minifier-css/package.js b/packages/minifier-css/package.js index d245e4a1f0..93d75bd005 100644 --- a/packages/minifier-css/package.js +++ b/packages/minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "CSS minifier", - version: "1.2.14-rc.7" + version: "1.2.14" }); Npm.depends({ diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 9931ae310f..b53c6ceb37 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "1.2.14-rc.7" + version: "1.2.14" }); Npm.depends({ diff --git a/packages/modules-runtime/package.js b/packages/modules-runtime/package.js index 29e38fbdf9..c18ad3de4d 100644 --- a/packages/modules-runtime/package.js +++ b/packages/modules-runtime/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules-runtime", - version: "0.7.6-rc.7", + version: "0.7.6", summary: "CommonJS module system", git: "https://github.com/benjamn/install", documentation: "README.md" diff --git a/packages/modules/package.js b/packages/modules/package.js index 8502eb2998..69ac7073bc 100644 --- a/packages/modules/package.js +++ b/packages/modules/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "modules", - version: "0.7.6-rc.7", + version: "0.7.6", summary: "CommonJS module system", documentation: "README.md" }); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index efe8333db8..11c05148eb 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.11-rc.7' + version: '1.1.11' }); Npm.depends({ diff --git a/packages/npm-bcrypt/package.js b/packages/npm-bcrypt/package.js index bd4691739b..c6025af0c6 100644 --- a/packages/npm-bcrypt/package.js +++ b/packages/npm-bcrypt/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Wrapper around the bcrypt npm package", - version: "0.9.1-rc.7", + version: "0.9.1", documentation: null }); diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 1736f93022..15a031d6fa 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,7 +3,7 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.46-rc.7', + version: '1.5.46', documentation: null }); diff --git a/packages/promise/package.js b/packages/promise/package.js index d5682f810e..9e4589b23f 100644 --- a/packages/promise/package.js +++ b/packages/promise/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "promise", - version: "0.8.4-rc.7", + version: "0.8.4", summary: "ECMAScript 2015 Promise polyfill with Fiber support", git: "https://github.com/meteor/promise", documentation: "README.md" diff --git a/packages/standard-minifier-css/package.js b/packages/standard-minifier-css/package.js index d943a4121e..cf53e0e1c0 100644 --- a/packages/standard-minifier-css/package.js +++ b/packages/standard-minifier-css/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-css', - version: '1.2.0-rc.7', + version: '1.2.0', summary: 'Standard css minifier used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 08545f5b0b..72c501e663 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '1.2.0-rc.7', + version: '1.2.0', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md' }); diff --git a/packages/static-html/package.js b/packages/static-html/package.js index 793ee538ec..4efeb39971 100644 --- a/packages/static-html/package.js +++ b/packages/static-html/package.js @@ -1,5 +1,5 @@ Package.describe({ - version: '1.1.12-rc.7', + version: '1.1.12', // Brief, one-line summary of the package. summary: 'Define static page content in .html files', git: 'https://github.com/meteor/meteor', diff --git a/packages/stylus/package.js b/packages/stylus/package.js index 876fe279a5..8285d3017f 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.5-rc.7" + version: "2.513.5" }); Package.registerBuildPlugin({ diff --git a/packages/templating/package.js b/packages/templating/package.js index 8688fbc23f..2e23bd1c2a 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Allows templates to be defined in .html files", - version: '1.2.14-rc.7' + version: '1.2.14' }); // Today, this package is closely intertwined with Handlebars, meaning diff --git a/packages/webapp/package.js b/packages/webapp/package.js index eab6166de2..6fcf9a54b8 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.11-rc.7' + version: '1.3.11' }); Npm.depends({connect: "2.30.2", diff --git a/packages/xmlbuilder/package.js b/packages/xmlbuilder/package.js index c075642bed..1caee9b139 100644 --- a/packages/xmlbuilder/package.js +++ b/packages/xmlbuilder/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "An XML builder for node.js similar to java-xmlbuilder.", - version: '2.5.14-rc.7' + version: '2.5.14' }); Npm.depends({ diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index 3940331155..79e671345a 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.0.1", + "version": "1.4.1", "recommended": false, "official": true, "description": "The Official Meteor Distribution", From 4618b3d8de240db33bb48c1f42eaabd47535183b Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 18 Aug 2016 16:39:47 -0400 Subject: [PATCH 130/688] Remove --no-bin-links flag from default `npm rebuild` arguments. After recent discussion on https://github.com/meteor/meteor/issues/7401, @glasser and I think the relatively obscure benefit of --no-bin-links is outweighed by the problems it causes for packages whose rebuild scripts need executable scripts installed in the node_modules/.bin/ directory. --- tools/static-assets/server/npm-rebuild-args.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/static-assets/server/npm-rebuild-args.js b/tools/static-assets/server/npm-rebuild-args.js index dab0ad56f8..8fb90463f1 100644 --- a/tools/static-assets/server/npm-rebuild-args.js +++ b/tools/static-assets/server/npm-rebuild-args.js @@ -2,11 +2,6 @@ var args = [ "rebuild", - // The --no-bin-links flag tells npm not to create symlinks in the - // node_modules/.bin/ directory when rebuilding packages, which helps - // avoid problems like https://github.com/meteor/meteor/issues/7401. - "--no-bin-links", - // The --update-binary flag tells node-pre-gyp to replace previously // installed local binaries with remote binaries: // https://github.com/mapbox/node-pre-gyp#options From b552011180a7d0c26a78531f23536cce8d250730 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 18 Aug 2016 17:13:48 -0400 Subject: [PATCH 131/688] Revert "Fix #7491 by wrapping child process in `script` on OSX" This reverts commit 98aaaed084fd87ab8003f0c2839705acdf965789. This change is no longer necessary with Node 4.5.0, which was included with Meteor 1.4.1. --- tools/cli/main.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/cli/main.js b/tools/cli/main.js index e5ab1f1d06..b04ad74fe6 100644 --- a/tools/cli/main.js +++ b/tools/cli/main.js @@ -493,14 +493,6 @@ var springboard = function (rel, options) { }).await()); } - // On OSX, there is a bug in node 4 when launching out to a node 0.10 process - // This should be fixed in the next release of node (we should then revert - // this change) https://github.com/meteor/meteor/issues/7491 - if (process.platform === 'darwin') { - newArgv.unshift('-q', '/dev/null', executable); - executable = 'script'; - } - // Now exec; we're not coming back. require('kexec')(executable, newArgv); throw Error('exec failed?'); From 88db65c8378336d20104792c7f2ce3604afa7d74 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 18 Aug 2016 17:31:21 -0400 Subject: [PATCH 132/688] Update modules test app to Meteor 1.4.1. --- .../apps/modules/.meteor/.finished-upgraders | 1 + tools/tests/apps/modules/.meteor/packages | 13 ++--- tools/tests/apps/modules/.meteor/release | 2 +- tools/tests/apps/modules/.meteor/versions | 49 ++++++++++--------- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/tools/tests/apps/modules/.meteor/.finished-upgraders b/tools/tests/apps/modules/.meteor/.finished-upgraders index 3e712bc5a9..a541808f2b 100644 --- a/tools/tests/apps/modules/.meteor/.finished-upgraders +++ b/tools/tests/apps/modules/.meteor/.finished-upgraders @@ -13,3 +13,4 @@ notices-for-facebook-graph-api-2 1.3.0-split-minifiers-package 1.3.5-remove-old-dev-bundle-link 1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package diff --git a/tools/tests/apps/modules/.meteor/packages b/tools/tests/apps/modules/.meteor/packages index 431c7291c4..e31a9d935f 100644 --- a/tools/tests/apps/modules/.meteor/packages +++ b/tools/tests/apps/modules/.meteor/packages @@ -6,19 +6,20 @@ meteor-base@1.0.4 # Packages every Meteor app needs to have mobile-experience@1.0.4 # Packages for a great mobile UX -mongo@1.1.10 # The database Meteor supports right now +mongo@1.1.11 # The database Meteor supports right now blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views session@1.1.6 # Client-side reactive dictionary for your app jquery@1.11.9 # Helpful client-side library tracker@1.1.0 # Meteor's client-side reactive programming library -es5-shim@4.6.13 # ECMAScript 5 compatibility for older browsers. -ecmascript@0.5.7 # Enable ECMAScript2015+ syntax in app code +es5-shim@4.6.14 # ECMAScript 5 compatibility for older browsers. +ecmascript@0.5.8 # Enable ECMAScript2015+ syntax in app code -coffeescript@1.2.3 +coffeescript@1.2.4 modules-test-package avital:mocha -standard-minifier-css@1.1.8 -standard-minifier-js@1.1.8 +standard-minifier-css@1.2.0 +standard-minifier-js@1.2.0 client-only-ecmascript modules-test-plugin +shell-server diff --git a/tools/tests/apps/modules/.meteor/release b/tools/tests/apps/modules/.meteor/release index 810628dc6d..30b2c590e3 100644 --- a/tools/tests/apps/modules/.meteor/release +++ b/tools/tests/apps/modules/.meteor/release @@ -1 +1 @@ -METEOR@1.4 +METEOR@1.4.1 diff --git a/tools/tests/apps/modules/.meteor/versions b/tools/tests/apps/modules/.meteor/versions index 7b73993d9a..3a2911a046 100644 --- a/tools/tests/apps/modules/.meteor/versions +++ b/tools/tests/apps/modules/.meteor/versions @@ -1,62 +1,62 @@ allow-deny@1.0.5 -autoupdate@1.2.11 +autoupdate@1.3.11 avital:mocha@2.1.0_10 -babel-compiler@6.9.0 -babel-runtime@0.1.10 +babel-compiler@6.9.1 +babel-runtime@0.1.11 base64@1.0.9 binary-heap@1.0.9 blaze@2.1.8 blaze-html-templates@1.0.4 blaze-tools@1.0.9 boilerplate-generator@1.0.9 -caching-compiler@1.1.6 +caching-compiler@1.1.7 caching-html-compiler@1.0.6 callback-hook@1.0.9 check@1.2.3 client-only-ecmascript@0.0.1 -coffeescript@1.2.3 +coffeescript@1.2.4 ddp@1.2.5 -ddp-client@1.2.9 +ddp-client@1.3.1 ddp-common@1.2.6 -ddp-server@1.2.10 +ddp-server@1.3.10 deps@1.0.12 diff-sequence@1.0.6 -ecmascript@0.5.7 -ecmascript-runtime@0.3.12 +ecmascript@0.5.8 +ecmascript-runtime@0.3.14 ejson@1.0.12 -es5-shim@4.6.13 +es5-shim@4.6.14 fastclick@1.0.12 geojson-utils@1.0.9 hot-code-push@1.0.4 html-tools@1.0.10 htmljs@1.0.10 -http@1.1.8 +http@1.2.9 id-map@1.0.8 jquery@1.11.9 launch-screen@1.0.12 livedata@1.0.18 -logging@1.1.14 -meteor@1.2.16 +logging@1.1.15 +meteor@1.2.17 meteor-base@1.0.4 -minifier-css@1.2.13 -minifier-js@1.2.13 +minifier-css@1.2.14 +minifier-js@1.2.14 minimongo@1.0.17 mobile-experience@1.0.4 mobile-status-bar@1.0.12 -modules@0.7.5 -modules-runtime@0.7.5 +modules@0.7.6 +modules-runtime@0.7.6 modules-test-package@0.0.1 modules-test-plugin@0.0.1 -mongo@1.1.10 +mongo@1.1.11 mongo-id@1.0.5 -npm-mongo@1.5.45 +npm-mongo@1.5.46 observe-sequence@1.0.12 ordered-dict@1.0.8 practicalmeteor:chai@2.1.0_1 practicalmeteor:loglevel@1.2.0_2 practicalmeteor:mocha-core@0.1.4 practicalmeteor:sinon@1.14.1_2 -promise@0.8.3 +promise@0.8.4 random@1.0.10 reactive-dict@1.1.8 reactive-var@1.0.10 @@ -64,16 +64,17 @@ reload@1.1.10 retry@1.0.8 routepolicy@1.0.11 session@1.1.6 +shell-server@0.2.1 spacebars@1.0.12 spacebars-compiler@1.0.12 -standard-minifier-css@1.1.8 -standard-minifier-js@1.1.8 -templating@1.1.14 +standard-minifier-css@1.2.0 +standard-minifier-js@1.2.0 +templating@1.2.14 templating-tools@1.0.4 tmeasday:test-reporter-helpers@0.2.1 tracker@1.1.0 ui@1.0.11 underscore@1.0.9 url@1.0.10 -webapp@1.3.10 +webapp@1.3.11 webapp-hashing@1.0.9 From d5c83aaf8fe59a09688f0d17a61b6e7f10ee7af2 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 22 Aug 2016 16:50:06 -0400 Subject: [PATCH 133/688] Don't try to use native tar command on Windows. Fixes #7689. --- tools/fs/files.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index ae83d5e3ab..ff3198512c 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -717,13 +717,10 @@ files.extractTarGz = function (buffer, destPath, options) { } const startTime = +new Date; - let promise = tryExtractWithNativeTar(buffer, tempDir, options); - if (process.platform === "win32") { - promise = promise.catch( - error => tryExtractWithNative7z(buffer, tempDir, options) - ); - } + let promise = process.platform === "win32" + ? tryExtractWithNative7z(buffer, tempDir, options) + : tryExtractWithNativeTar(buffer, tempDir, options) promise = promise.catch( error => tryExtractWithNpmTar(buffer, tempDir, options) From 5fa59d2b8b61fe408cf1ec34d639a4df709bddd4 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 23 Aug 2016 11:44:21 +1000 Subject: [PATCH 134/688] Bumping version of the `npm-mongo` package for #7594 This was a fairly serious issue with the mongo driver --- packages/npm-mongo/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 15a031d6fa..10da6b35e8 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,12 +3,12 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.46', + version: '1.5.47', documentation: null }); Npm.depends({ - mongodb: "2.2.4" + mongodb: "2.2.7" }); Package.onUse(function (api) { From 7f8ecb6b1c80f3872b226cc60a4727b9bc020f6f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 23 Aug 2016 11:36:00 -0400 Subject: [PATCH 135/688] Update npm-mongo shrinkwrap. --- .../.npm/package/npm-shrinkwrap.json | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/packages/npm-mongo/.npm/package/npm-shrinkwrap.json b/packages/npm-mongo/.npm/package/npm-shrinkwrap.json index e327314325..35c9428649 100644 --- a/packages/npm-mongo/.npm/package/npm-shrinkwrap.json +++ b/packages/npm-mongo/.npm/package/npm-shrinkwrap.json @@ -1,9 +1,14 @@ { "dependencies": { "bson": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-0.5.2.tgz", - "from": "bson@>=0.5.1 <0.6.0" + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-0.5.4.tgz", + "from": "bson@>=0.5.3 <0.6.0" + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "from": "buffer-shims@>=1.0.0 <2.0.0" }, "core-util-is": { "version": "1.0.2", @@ -11,9 +16,9 @@ "from": "core-util-is@>=1.0.0 <1.1.0" }, "es6-promise": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "from": "es6-promise@3.0.2" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "from": "es6-promise@3.2.1" }, "inherits": { "version": "2.0.1", @@ -21,24 +26,29 @@ "from": "inherits@>=2.0.1 <2.1.0" }, "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "from": "isarray@0.0.1" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "from": "isarray@>=1.0.0 <1.1.0" }, "mongodb": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.4.tgz", - "from": "mongodb@2.2.4" + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.7.tgz", + "from": "mongodb@2.2.7" }, "mongodb-core": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.0.6.tgz", - "from": "mongodb-core@2.0.6" + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.0.9.tgz", + "from": "mongodb-core@2.0.9" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "from": "process-nextick-args@>=1.0.6 <1.1.0" }, "readable-stream": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", - "from": "readable-stream@1.0.31" + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", + "from": "readable-stream@2.1.5" }, "require_optional": { "version": "1.0.0", @@ -59,6 +69,11 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "from": "string_decoder@>=0.10.0 <0.11.0" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "from": "util-deprecate@>=1.0.1 <1.1.0" } } } From 659706f61d4e979613d86a92320c9a0ea2033a3e Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 23 Aug 2016 11:50:38 -0400 Subject: [PATCH 136/688] Bump package versions for 1.4.2-beta.0 release. --- packages/meteor-tool/package.js | 2 +- packages/npm-mongo/package.js | 2 +- scripts/admin/meteor-release-experimental.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 901bfc0808..4bd08c3606 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.4.1' + version: '1.4.2-beta.0' }); Package.includeTool(); diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 10da6b35e8..1cdc793330 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,7 +3,7 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.47', + version: '1.5.48-beta.0', documentation: null }); diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 2a7ca869b9..7f2569d003 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.1-rc.7", + "version": "1.4.2-beta.0", "recommended": false, "official": false, "description": "Meteor" From 532a7feafabac8d0853b51b117ba35318840886e Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Wed, 25 May 2016 14:15:53 +0800 Subject: [PATCH 137/688] Take callbacks for all accounts-client and handle them consistently Where possible, only throw if there is no callback and we know on the client that the arguments are wrong. Add some tests for this behavior. --- packages/accounts-password/password_client.js | 44 +++++----- packages/accounts-password/password_tests.js | 83 +++++++++++++++++++ 2 files changed, 108 insertions(+), 19 deletions(-) diff --git a/packages/accounts-password/password_client.js b/packages/accounts-password/password_client.js index 83f1161984..bc1478507f 100644 --- a/packages/accounts-password/password_client.js +++ b/packages/accounts-password/password_client.js @@ -1,3 +1,12 @@ +// Used in the various functions below to handle errors consistently +function reportError(error, callback) { + if (callback) { + callback(error); + } else { + throw error; + } +}; + // Attempt to log in with a password. // // @param selector {String|Object} One of the following: @@ -55,7 +64,7 @@ Meteor.loginWithPassword = function (selector, password, callback) { }, callback); } else if (error) { - callback && callback(error); + reportError(error, callback); } else { callback && callback(); } @@ -83,9 +92,9 @@ var srpUpgradePath = function (options, callback) { details = EJSON.parse(options.upgradeError.details); } catch (e) {} if (!(details && details.format === 'srp')) { - callback && callback( + reportError( new Meteor.Error(400, "Password is old. Please reset your " + - "password.")); + "password."), callback); } else { Accounts.callLoginMethod({ methodArguments: [{ @@ -98,7 +107,6 @@ var srpUpgradePath = function (options, callback) { } }; - // Attempt to log in as a new user. /** @@ -118,8 +126,7 @@ Accounts.createUser = function (options, callback) { if (typeof options.password !== 'string') throw new Error("options.password must be a string"); if (!options.password) { - callback(new Meteor.Error(400, "Password may not be empty")); - return; + return reportError(new Meteor.Error(400, "Password may not be empty"), callback); } // Replace password with the hashed password. @@ -150,14 +157,12 @@ Accounts.createUser = function (options, callback) { */ Accounts.changePassword = function (oldPassword, newPassword, callback) { if (!Meteor.user()) { - callback && callback(new Error("Must be logged in to change password.")); - return; + return reportError(new Error("Must be logged in to change password."), callback); } check(newPassword, String); if (!newPassword) { - callback(new Meteor.Error(400, "Password may not be empty")); - return; + return reportError(new Meteor.Error(400, "Password may not be empty"), callback); } Accounts.connection.apply( @@ -177,7 +182,7 @@ Accounts.changePassword = function (oldPassword, newPassword, callback) { plaintextPassword: oldPassword }, function (err) { if (err) { - callback && callback(err); + reportError(err, callback); } else { // Now that we've successfully migrated from srp to // bcrypt, try changing the password again. @@ -186,8 +191,8 @@ Accounts.changePassword = function (oldPassword, newPassword, callback) { }); } else { // A normal error, not an error telling us to upgrade to bcrypt - callback && callback( - error || new Error("No result from changePassword.")); + reportError( + error || new Error("No result from changePassword."), callback); } } else { callback && callback(); @@ -212,8 +217,9 @@ Accounts.changePassword = function (oldPassword, newPassword, callback) { * @importFromPackage accounts-base */ Accounts.forgotPassword = function(options, callback) { - if (!options.email) - throw new Error("Must pass options.email"); + if (!options.email) { + return reportError(new Meteor.Error(400, "Must pass options.email"), callback); + } Accounts.connection.call("forgotPassword", options, callback); }; @@ -237,8 +243,7 @@ Accounts.resetPassword = function(token, newPassword, callback) { check(newPassword, String); if (!newPassword) { - callback(new Meteor.Error(400, "Password may not be empty")); - return; + return reportError(new Meteor.Error(400, "Password may not be empty"), callback); } Accounts.callLoginMethod({ @@ -261,8 +266,9 @@ Accounts.resetPassword = function(token, newPassword, callback) { * @importFromPackage accounts-base */ Accounts.verifyEmail = function(token, callback) { - if (!token) - throw new Error("Need to pass token"); + if (!token) { + return reportError(new Meteor.Error(400, "Need to pass token"), callback); + } Accounts.callLoginMethod({ methodName: 'verifyEmail', diff --git a/packages/accounts-password/password_tests.js b/packages/accounts-password/password_tests.js index 61c78060e4..0f2fc81086 100644 --- a/packages/accounts-password/password_tests.js +++ b/packages/accounts-password/password_tests.js @@ -410,6 +410,13 @@ if (Meteor.isClient) (function () { "email", [ createUserStep, logoutStep, + // Create user error without callback should not throw error + function (test, expect) { + this.newUsername = 'adalovelace' + this.randomSuffix; + Accounts.createUser( + { username: this.newUsername, password: '' } + ); + }, // Attempting to create another user with an email that only differs in // case should fail function (test, expect) { @@ -468,6 +475,14 @@ if (Meteor.isClient) (function () { test.equal(Meteor.user().username, self.username); })); }, + // change password with bad old password, but no callback so no error + function (test, expect) { + Accounts.changePassword('wrong', 'doesntmatter'); + }, + // change password with blank new password, but no callback so no error + function (test, expect) { + Accounts.changePassword(this.password, ''); + }, // change password with good old password. function (test, expect) { Accounts.changePassword(this.password, this.password2, @@ -544,6 +559,74 @@ if (Meteor.isClient) (function () { }, 10 * 1000, 100); } ]); + + + testAsyncMulti("passwords - forgotPassword client return error when empty email", [ + function (test, expect) { + // setup + this.email = ''; + }, + // forgotPassword called on client with blank email + function (test, expect) { + Accounts.forgotPassword( + { email: this.email }, expect(function (error) { + test.isTrue(error); + })); + }, + // forgotPassword called on client with blank email, no callback so no error + function (test, expect) { + Accounts.forgotPassword({ email: this.email }); + }, + ]); + + testAsyncMulti("passwords - verifyEmail client return error when empty token", [ + function (test, expect) { + // setup + this.token = ''; + }, + // verifyEmail called on client with blank token + function (test, expect) { + Accounts.verifyEmail( + this.token, expect(function (error) { + test.isTrue(error); + })); + }, + // verifyEmail called on client with blank token, no callback so no error + function (test, expect) { + Accounts.verifyEmail(this.token); + }, + ]); + + testAsyncMulti("passwords - resetPassword errors", [ + function (test, expect) { + // setup + this.token = ''; + this.newPassword = 'nonblankpassword'; + }, + // resetPassword called on client with blank token + function (test, expect) { + Accounts.resetPassword( + this.token, this.newPassword, expect(function (error) { + test.isTrue(error); + })); + }, + function (test, expect) { + // setup + this.token = 'nonblank-token'; + this.newPassword = ''; + }, + // resetPassword called on client with blank password + function (test, expect) { + Accounts.resetPassword( + this.token, this.newPassword, expect(function (error) { + test.isTrue(error); + })); + }, + // resetPassword called on client with blank password, no callback so no error + function (test, expect) { + Accounts.resetPassword(this.token, this.newPassword); + }, + ]); testAsyncMulti("passwords - new user hooks", [ From c8d1f2009f4414184d61efb2ba928c969142cb48 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Sat, 30 Jul 2016 18:50:49 +0800 Subject: [PATCH 138/688] Further tests to fix accounts callback / throwing behavior --- packages/accounts-password/password_tests.js | 36 +++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/accounts-password/password_tests.js b/packages/accounts-password/password_tests.js index 0f2fc81086..a60cb25fb9 100644 --- a/packages/accounts-password/password_tests.js +++ b/packages/accounts-password/password_tests.js @@ -410,12 +410,12 @@ if (Meteor.isClient) (function () { "email", [ createUserStep, logoutStep, - // Create user error without callback should not throw error + // Create user error without callback should throw error function (test, expect) { this.newUsername = 'adalovelace' + this.randomSuffix; - Accounts.createUser( - { username: this.newUsername, password: '' } - ); + test.throws(function(){ + Accounts.createUser({ username: this.newUsername, password: '' }); + }, /Password may not be empty/); }, // Attempting to create another user with an email that only differs in // case should fail @@ -475,13 +475,11 @@ if (Meteor.isClient) (function () { test.equal(Meteor.user().username, self.username); })); }, - // change password with bad old password, but no callback so no error + // change password with blank new password function (test, expect) { - Accounts.changePassword('wrong', 'doesntmatter'); - }, - // change password with blank new password, but no callback so no error - function (test, expect) { - Accounts.changePassword(this.password, ''); + test.throws(function(){ + Accounts.changePassword(this.password, ''); + }, /Password may not be empty/); }, // change password with good old password. function (test, expect) { @@ -573,9 +571,11 @@ if (Meteor.isClient) (function () { test.isTrue(error); })); }, - // forgotPassword called on client with blank email, no callback so no error + // forgotPassword called on client with blank email and no callback. function (test, expect) { - Accounts.forgotPassword({ email: this.email }); + test.throws(function(){ + Accounts.forgotPassword({ email: this.email }); + }, /Must pass options\.email/); }, ]); @@ -591,9 +591,11 @@ if (Meteor.isClient) (function () { test.isTrue(error); })); }, - // verifyEmail called on client with blank token, no callback so no error + // verifyEmail called on client with blank token and no callback. function (test, expect) { - Accounts.verifyEmail(this.token); + test.throws(function(){ + Accounts.verifyEmail(this.token); + }, /Need to pass token/); }, ]); @@ -622,9 +624,11 @@ if (Meteor.isClient) (function () { test.isTrue(error); })); }, - // resetPassword called on client with blank password, no callback so no error + // resetPassword called on client with blank password and no callback. function (test, expect) { - Accounts.resetPassword(this.token, this.newPassword); + test.throws(function(){ + Accounts.resetPassword(this.token, this.newPassword); + }, /Match error: Expected string, got undefined/); }, ]); From 0757e2195814a36517004c06b346e61b0a0b6986 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Thu, 26 May 2016 12:12:53 +0800 Subject: [PATCH 139/688] Update History.md --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index d2041e0c95..76092a769e 100644 --- a/History.md +++ b/History.md @@ -390,6 +390,7 @@ * Insert a `Date` header into emails by default: https://github.com/meteor/meteor/pull/6916/files * `meteor test` now supports setting the bind address using `--port IP:PORT` the same as `meteor run` [PR #6964](https://github.com/meteor/meteor/pull/6964) [Issue #6961](https://github.com/meteor/meteor/issues/6961) +* Accounts.forgotPassword and .verifyEmail no longer throw errors if callback is provided. [Issue #5664](https://github.com/meteor/meteor/issues/5664) [Origin PR #5681](https://github.com/meteor/meteor/pull/5681) [Merged PR](https://github.com/meteor/meteor/pull/7117) * `Meteor.apply` now takes a `noRetry` option to opt-out of automatically retrying non-idempotent methods on connection blips: [PR #6180](https://github.com/meteor/meteor/pull/6180) From d1edbebbf526eb472378c6e25b101421384276e7 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 24 Aug 2016 11:48:09 +1000 Subject: [PATCH 140/688] Set a minimum version for `npm-mongo` package in `mongo` package So when we do a release, the constraint will force users to get the new npm-mongo package. We likely will seek a better solution to this kind of problem in the future --- packages/mongo/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mongo/package.js b/packages/mongo/package.js index 11c05148eb..9da2fe1f48 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.11' + version: '1.1.12' }); Npm.depends({ @@ -21,7 +21,7 @@ Npm.strip({ }); Package.onUse(function (api) { - api.use('npm-mongo', 'server'); + api.use('npm-mongo@1.5.47', 'server'); api.use('allow-deny'); api.use([ From 6eec080025814f41352d8dded5e1f712fd1dedc2 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 24 Aug 2016 12:23:42 +1000 Subject: [PATCH 141/688] Preparing the 1.4.1.1 release --- History.md | 6 ++++++ scripts/admin/meteor-release-official.json | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index d2041e0c95..ce5a62aa2a 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,11 @@ ## v.NEXT +## v1.4.1.1 + +* Update the version of our Node MongoDB driver to 2.2.7 to fix a bug in + reconnection logic, leading to some `update` and `remove` commands being + treated as `insert`s. [#7594](https://github.com/meteor/meteor/issue/7594) + ## v1.4.1 * Node has been upgraded to 4.5.0. diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index 79e671345a..3f211afbdd 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,8 +1,8 @@ { "track": "METEOR", - "version": "1.4.1", + "version": "1.4.1.1", "recommended": false, "official": true, "description": "The Official Meteor Distribution", - "patchFrom": ["1.4"] + "patchFrom": ["1.4.1"] } From e9a57a9bad32cbb971cdda79b5828d8b2f1a0a94 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 24 Aug 2016 14:54:37 +1000 Subject: [PATCH 142/688] Bumped node module version again for 1.4.1.1 release --- packages/coffeescript/package.js | 2 +- packages/meteor-tool/package.js | 2 +- packages/mongo/package.js | 2 +- .../.npm/package/npm-shrinkwrap.json | 51 ++++++++++++------- packages/npm-mongo/package.js | 4 +- 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index e3cc7cdcaa..3feb3ff339 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.2.4" + version: "1.2.4_1" }); Package.registerBuildPlugin({ diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 901bfc0808..0ac0d2148c 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.4.1' + version: '1.4.1_1' }); Package.includeTool(); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index 9da2fe1f48..3e420265e4 100644 --- a/packages/mongo/package.js +++ b/packages/mongo/package.js @@ -21,7 +21,7 @@ Npm.strip({ }); Package.onUse(function (api) { - api.use('npm-mongo@1.5.47', 'server'); + api.use('npm-mongo@1.5.48', 'server'); api.use('allow-deny'); api.use([ diff --git a/packages/npm-mongo/.npm/package/npm-shrinkwrap.json b/packages/npm-mongo/.npm/package/npm-shrinkwrap.json index e327314325..50563e4ea7 100644 --- a/packages/npm-mongo/.npm/package/npm-shrinkwrap.json +++ b/packages/npm-mongo/.npm/package/npm-shrinkwrap.json @@ -1,9 +1,14 @@ { "dependencies": { "bson": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-0.5.2.tgz", - "from": "bson@>=0.5.1 <0.6.0" + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-0.5.4.tgz", + "from": "bson@>=0.5.4 <0.6.0" + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "from": "buffer-shims@>=1.0.0 <2.0.0" }, "core-util-is": { "version": "1.0.2", @@ -11,9 +16,9 @@ "from": "core-util-is@>=1.0.0 <1.1.0" }, "es6-promise": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "from": "es6-promise@3.0.2" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "from": "es6-promise@3.2.1" }, "inherits": { "version": "2.0.1", @@ -21,24 +26,29 @@ "from": "inherits@>=2.0.1 <2.1.0" }, "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "from": "isarray@0.0.1" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "from": "isarray@>=1.0.0 <1.1.0" }, "mongodb": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.4.tgz", - "from": "mongodb@2.2.4" + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.8.tgz", + "from": "mongodb@2.2.8" }, "mongodb-core": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.0.6.tgz", - "from": "mongodb-core@2.0.6" + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.0.10.tgz", + "from": "mongodb-core@2.0.10" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "from": "process-nextick-args@>=1.0.6 <1.1.0" }, "readable-stream": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", - "from": "readable-stream@1.0.31" + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", + "from": "readable-stream@2.1.5" }, "require_optional": { "version": "1.0.0", @@ -59,6 +69,11 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "from": "string_decoder@>=0.10.0 <0.11.0" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "from": "util-deprecate@>=1.0.1 <1.1.0" } } } diff --git a/packages/npm-mongo/package.js b/packages/npm-mongo/package.js index 10da6b35e8..86dab645cb 100644 --- a/packages/npm-mongo/package.js +++ b/packages/npm-mongo/package.js @@ -3,12 +3,12 @@ Package.describe({ summary: "Wrapper around the mongo npm package", - version: '1.5.47', + version: '1.5.48', documentation: null }); Npm.depends({ - mongodb: "2.2.7" + mongodb: "2.2.8" }); Package.onUse(function (api) { From afc165e00a8096a59dd8a77ab216bf968f04fa54 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 9 Aug 2016 14:03:24 +1000 Subject: [PATCH 143/688] Literally just deleted packages --- packages/blaze-html-templates/README.md | 9 - packages/blaze-html-templates/package.js | 25 - packages/blaze-tools/.gitignore | 1 - packages/blaze-tools/README.md | 4 - packages/blaze-tools/package.js | 24 - packages/blaze-tools/preamble.js | 1 - packages/blaze-tools/tojs.js | 156 - packages/blaze-tools/token_tests.js | 78 - packages/blaze-tools/tokens.js | 193 - packages/blaze/.gitignore | 1 - packages/blaze/README.md | 318 -- packages/blaze/attrs.js | 365 -- packages/blaze/backcompat.js | 18 - packages/blaze/builtins.js | 354 -- packages/blaze/dombackend.js | 179 - packages/blaze/domrange.js | 485 --- packages/blaze/events.js | 204 - packages/blaze/exceptions.js | 56 - packages/blaze/lookup.js | 238 -- packages/blaze/materializer.js | 191 - packages/blaze/microscore.js | 116 - packages/blaze/package.js | 55 - packages/blaze/preamble.js | 32 - packages/blaze/render_tests.js | 688 ---- packages/blaze/template.js | 565 --- packages/blaze/view.js | 900 ----- packages/blaze/view_tests.js | 59 - packages/caching-html-compiler/README.md | 37 - .../caching-html-compiler.js | 141 - packages/caching-html-compiler/package.js | 21 - packages/html-tools/.gitignore | 1 - packages/html-tools/README.md | 139 - packages/html-tools/charref.js | 2414 ----------- packages/html-tools/charref_tests.js | 114 - packages/html-tools/package.js | 29 - packages/html-tools/parse.js | 358 -- packages/html-tools/parse_tests.js | 404 -- packages/html-tools/scanner.js | 82 - packages/html-tools/templatetag.js | 29 - packages/html-tools/tokenize.js | 513 --- packages/html-tools/tokenize_tests.js | 344 -- packages/html-tools/utils.js | 50 - packages/htmljs/.gitignore | 1 - packages/htmljs/README.md | 427 -- packages/htmljs/html.js | 268 -- packages/htmljs/htmljs_test.js | 87 - packages/htmljs/package.js | 21 - packages/htmljs/preamble.js | 4 - packages/htmljs/visitors.js | 331 -- packages/spacebars-compiler/.gitignore | 1 - packages/spacebars-compiler/README.md | 15 - packages/spacebars-compiler/codegen.js | 389 -- packages/spacebars-compiler/compile_tests.js | 114 - packages/spacebars-compiler/compiler.js | 116 - .../compiler_output_tests.coffee | 296 -- packages/spacebars-compiler/optimizer.js | 189 - packages/spacebars-compiler/package.js | 38 - packages/spacebars-compiler/react.js | 44 - .../spacebars-compiler/spacebars_tests.js | 317 -- packages/spacebars-compiler/templatetag.js | 506 --- packages/spacebars-tests/.gitignore | 1 - packages/spacebars-tests/README.md | 1 - .../assets/markdown_basic.html | 49 - .../assets/markdown_each1.html | 15 - .../assets/markdown_each2.html | 19 - .../spacebars-tests/assets/markdown_if1.html | 19 - .../spacebars-tests/assets/markdown_if2.html | 19 - packages/spacebars-tests/old_templates.js | 2058 ---------- .../spacebars-tests/old_templates_tests.js | 2749 ------------- packages/spacebars-tests/package.js | 46 - packages/spacebars-tests/template_tests.html | 1160 ------ packages/spacebars-tests/template_tests.js | 3512 ----------------- .../spacebars-tests/template_tests_server.js | 28 - .../spacebars-tests/templating_tests.html | 224 -- packages/spacebars-tests/templating_tests.js | 619 --- packages/spacebars/.gitignore | 1 - packages/spacebars/README.md | 9 - packages/spacebars/package.js | 23 - packages/spacebars/spacebars-runtime.js | 283 -- packages/static-html/README.md | 10 - packages/static-html/package.js | 29 - packages/static-html/static-html.js | 90 - packages/templating-tools/README.md | 102 - packages/templating-tools/code-generation.js | 18 - .../compile-tags-with-spacebars.js | 104 - .../templating-tools/html-scanner-tests.js | 189 - packages/templating-tools/html-scanner.js | 172 - packages/templating-tools/package.js | 47 - packages/templating-tools/templating-tools.js | 4 - .../templating-tools/throw-compile-error.js | 11 - packages/templating/.gitignore | 1 - packages/templating/README.md | 13 - packages/templating/dynamic.html | 23 - packages/templating/dynamic.js | 39 - packages/templating/dynamic_tests.html | 61 - packages/templating/dynamic_tests.js | 239 -- packages/templating/package.js | 48 - .../templating/plugin/compile-templates.js | 9 - packages/templating/templating.js | 78 - 99 files changed, 25277 deletions(-) delete mode 100644 packages/blaze-html-templates/README.md delete mode 100644 packages/blaze-html-templates/package.js delete mode 100644 packages/blaze-tools/.gitignore delete mode 100644 packages/blaze-tools/README.md delete mode 100644 packages/blaze-tools/package.js delete mode 100644 packages/blaze-tools/preamble.js delete mode 100644 packages/blaze-tools/tojs.js delete mode 100644 packages/blaze-tools/token_tests.js delete mode 100644 packages/blaze-tools/tokens.js delete mode 100644 packages/blaze/.gitignore delete mode 100644 packages/blaze/README.md delete mode 100644 packages/blaze/attrs.js delete mode 100644 packages/blaze/backcompat.js delete mode 100644 packages/blaze/builtins.js delete mode 100644 packages/blaze/dombackend.js delete mode 100644 packages/blaze/domrange.js delete mode 100644 packages/blaze/events.js delete mode 100644 packages/blaze/exceptions.js delete mode 100644 packages/blaze/lookup.js delete mode 100644 packages/blaze/materializer.js delete mode 100644 packages/blaze/microscore.js delete mode 100644 packages/blaze/package.js delete mode 100644 packages/blaze/preamble.js delete mode 100644 packages/blaze/render_tests.js delete mode 100644 packages/blaze/template.js delete mode 100644 packages/blaze/view.js delete mode 100644 packages/blaze/view_tests.js delete mode 100644 packages/caching-html-compiler/README.md delete mode 100644 packages/caching-html-compiler/caching-html-compiler.js delete mode 100644 packages/caching-html-compiler/package.js delete mode 100644 packages/html-tools/.gitignore delete mode 100644 packages/html-tools/README.md delete mode 100644 packages/html-tools/charref.js delete mode 100644 packages/html-tools/charref_tests.js delete mode 100644 packages/html-tools/package.js delete mode 100644 packages/html-tools/parse.js delete mode 100644 packages/html-tools/parse_tests.js delete mode 100644 packages/html-tools/scanner.js delete mode 100644 packages/html-tools/templatetag.js delete mode 100644 packages/html-tools/tokenize.js delete mode 100644 packages/html-tools/tokenize_tests.js delete mode 100644 packages/html-tools/utils.js delete mode 100644 packages/htmljs/.gitignore delete mode 100644 packages/htmljs/README.md delete mode 100644 packages/htmljs/html.js delete mode 100644 packages/htmljs/htmljs_test.js delete mode 100644 packages/htmljs/package.js delete mode 100644 packages/htmljs/preamble.js delete mode 100644 packages/htmljs/visitors.js delete mode 100644 packages/spacebars-compiler/.gitignore delete mode 100644 packages/spacebars-compiler/README.md delete mode 100644 packages/spacebars-compiler/codegen.js delete mode 100644 packages/spacebars-compiler/compile_tests.js delete mode 100644 packages/spacebars-compiler/compiler.js delete mode 100644 packages/spacebars-compiler/compiler_output_tests.coffee delete mode 100644 packages/spacebars-compiler/optimizer.js delete mode 100644 packages/spacebars-compiler/package.js delete mode 100644 packages/spacebars-compiler/react.js delete mode 100644 packages/spacebars-compiler/spacebars_tests.js delete mode 100644 packages/spacebars-compiler/templatetag.js delete mode 100644 packages/spacebars-tests/.gitignore delete mode 100644 packages/spacebars-tests/README.md delete mode 100644 packages/spacebars-tests/assets/markdown_basic.html delete mode 100644 packages/spacebars-tests/assets/markdown_each1.html delete mode 100644 packages/spacebars-tests/assets/markdown_each2.html delete mode 100644 packages/spacebars-tests/assets/markdown_if1.html delete mode 100644 packages/spacebars-tests/assets/markdown_if2.html delete mode 100644 packages/spacebars-tests/old_templates.js delete mode 100644 packages/spacebars-tests/old_templates_tests.js delete mode 100644 packages/spacebars-tests/package.js delete mode 100644 packages/spacebars-tests/template_tests.html delete mode 100644 packages/spacebars-tests/template_tests.js delete mode 100644 packages/spacebars-tests/template_tests_server.js delete mode 100644 packages/spacebars-tests/templating_tests.html delete mode 100644 packages/spacebars-tests/templating_tests.js delete mode 100644 packages/spacebars/.gitignore delete mode 100644 packages/spacebars/README.md delete mode 100644 packages/spacebars/package.js delete mode 100644 packages/spacebars/spacebars-runtime.js delete mode 100644 packages/static-html/README.md delete mode 100644 packages/static-html/package.js delete mode 100644 packages/static-html/static-html.js delete mode 100644 packages/templating-tools/README.md delete mode 100644 packages/templating-tools/code-generation.js delete mode 100644 packages/templating-tools/compile-tags-with-spacebars.js delete mode 100644 packages/templating-tools/html-scanner-tests.js delete mode 100644 packages/templating-tools/html-scanner.js delete mode 100644 packages/templating-tools/package.js delete mode 100644 packages/templating-tools/templating-tools.js delete mode 100644 packages/templating-tools/throw-compile-error.js delete mode 100644 packages/templating/.gitignore delete mode 100644 packages/templating/README.md delete mode 100644 packages/templating/dynamic.html delete mode 100644 packages/templating/dynamic.js delete mode 100644 packages/templating/dynamic_tests.html delete mode 100644 packages/templating/dynamic_tests.js delete mode 100644 packages/templating/package.js delete mode 100644 packages/templating/plugin/compile-templates.js delete mode 100644 packages/templating/templating.js diff --git a/packages/blaze-html-templates/README.md b/packages/blaze-html-templates/README.md deleted file mode 100644 index 84ad905655..0000000000 --- a/packages/blaze-html-templates/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# blaze-html-templates - -A meta-package that includes everything you need to compile and run Meteor templates with Spacebars and Blaze. - -For more details, see the documentation of the component packages: - -- [templating](https://atmospherejs.com/meteor/templating): compiles `.html` files -- [blaze](https://atmospherejs.com/meteor/blaze): the runtime library -- [spacebars](https://atmospherejs.com/meteor/spacebars): the templating language diff --git a/packages/blaze-html-templates/package.js b/packages/blaze-html-templates/package.js deleted file mode 100644 index edc01346bc..0000000000 --- a/packages/blaze-html-templates/package.js +++ /dev/null @@ -1,25 +0,0 @@ -Package.describe({ - name: 'blaze-html-templates', - version: '1.0.4', - // Brief, one-line summary of the package. - summary: 'Compile HTML templates into reactive UI with Meteor Blaze', - // By default, Meteor will default to using README.md for documentation. - // To avoid submitting documentation, set this field to null. - documentation: 'README.md' -}); - -Package.onUse(function(api) { - api.imply([ - // A library for reactive user interfaces - 'blaze', - - // The following packages are basically empty shells that just exist to - // satisfy code checking for the existence of a package. Rest assured that - // they are not adding any bloat to your bundle. - 'ui', // XXX COMPAT WITH PACKAGES BUILT FOR 0.9.0. - 'spacebars', // XXX COMPAT WITH PACKAGES BUILT FOR 0.9.0 - - // Compile .html files into Blaze reactive views - 'templating' - ]); -}); diff --git a/packages/blaze-tools/.gitignore b/packages/blaze-tools/.gitignore deleted file mode 100644 index 677a6fc263..0000000000 --- a/packages/blaze-tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.build* diff --git a/packages/blaze-tools/README.md b/packages/blaze-tools/README.md deleted file mode 100644 index 4b92b835aa..0000000000 --- a/packages/blaze-tools/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# blaze-tools - -Compile-time utilities that are likely to be useful to any package -that compiles templates for Blaze. diff --git a/packages/blaze-tools/package.js b/packages/blaze-tools/package.js deleted file mode 100644 index c6c90f3071..0000000000 --- a/packages/blaze-tools/package.js +++ /dev/null @@ -1,24 +0,0 @@ -Package.describe({ - summary: "Compile-time tools for Blaze", - version: '1.0.9' -}); - -Package.onUse(function (api) { - api.export('BlazeTools'); - - api.use('htmljs'); - api.use('underscore'); - - api.addFiles(['preamble.js', - 'tokens.js', - 'tojs.js']); -}); - -Package.onTest(function (api) { - api.use('blaze-tools'); - api.use('tinytest'); - api.use('underscore'); - api.use('html-tools'); - - api.addFiles(['token_tests.js']); -}); diff --git a/packages/blaze-tools/preamble.js b/packages/blaze-tools/preamble.js deleted file mode 100644 index 2211e646ab..0000000000 --- a/packages/blaze-tools/preamble.js +++ /dev/null @@ -1 +0,0 @@ -BlazeTools = {}; diff --git a/packages/blaze-tools/tojs.js b/packages/blaze-tools/tojs.js deleted file mode 100644 index 730dc24d54..0000000000 --- a/packages/blaze-tools/tojs.js +++ /dev/null @@ -1,156 +0,0 @@ - -BlazeTools.EmitCode = function (value) { - if (! (this instanceof BlazeTools.EmitCode)) - // called without `new` - return new BlazeTools.EmitCode(value); - - if (typeof value !== 'string') - throw new Error('BlazeTools.EmitCode must be constructed with a string'); - - this.value = value; -}; -BlazeTools.EmitCode.prototype.toJS = function (visitor) { - return this.value; -}; - -// Turns any JSONable value into a JavaScript literal. -toJSLiteral = function (obj) { - // See for `\u2028\u2029`. - // Also escape Unicode surrogates. - return (JSON.stringify(obj) - .replace(/[\u2028\u2029\ud800-\udfff]/g, function (c) { - return '\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4); - })); -}; -BlazeTools.toJSLiteral = toJSLiteral; - - - -var jsReservedWordSet = (function (set) { - _.each("abstract else instanceof super boolean enum int switch break export interface synchronized byte extends let this case false long throw catch final native throws char finally new transient class float null true const for package try continue function private typeof debugger goto protected var default if public void delete implements return volatile do import short while double in static with".split(' '), function (w) { - set[w] = 1; - }); - return set; -})({}); - -toObjectLiteralKey = function (k) { - if (/^[a-zA-Z$_][a-zA-Z$0-9_]*$/.test(k) && jsReservedWordSet[k] !== 1) - return k; - return toJSLiteral(k); -}; -BlazeTools.toObjectLiteralKey = toObjectLiteralKey; - -var hasToJS = function (x) { - return x.toJS && (typeof (x.toJS) === 'function'); -}; - -ToJSVisitor = HTML.Visitor.extend(); -ToJSVisitor.def({ - visitNull: function (nullOrUndefined) { - return 'null'; - }, - visitPrimitive: function (stringBooleanOrNumber) { - return toJSLiteral(stringBooleanOrNumber); - }, - visitArray: function (array) { - var parts = []; - for (var i = 0; i < array.length; i++) - parts.push(this.visit(array[i])); - return '[' + parts.join(', ') + ']'; - }, - visitTag: function (tag) { - return this.generateCall(tag.tagName, tag.attrs, tag.children); - }, - visitComment: function (comment) { - return this.generateCall('HTML.Comment', null, [comment.value]); - }, - visitCharRef: function (charRef) { - return this.generateCall('HTML.CharRef', - {html: charRef.html, str: charRef.str}); - }, - visitRaw: function (raw) { - return this.generateCall('HTML.Raw', null, [raw.value]); - }, - visitObject: function (x) { - if (hasToJS(x)) { - return x.toJS(this); - } - - throw new Error("Unexpected object in HTMLjs in toJS: " + x); - }, - generateCall: function (name, attrs, children) { - var tagSymbol; - if (name.indexOf('.') >= 0) { - tagSymbol = name; - } else if (HTML.isTagEnsured(name)) { - tagSymbol = 'HTML.' + HTML.getSymbolName(name); - } else { - tagSymbol = 'HTML.getTag(' + toJSLiteral(name) + ')'; - } - - var attrsArray = null; - if (attrs) { - attrsArray = []; - var needsHTMLAttrs = false; - if (HTML.isArray(attrs)) { - var attrsArray = []; - for (var i = 0; i < attrs.length; i++) { - var a = attrs[i]; - if (hasToJS(a)) { - attrsArray.push(a.toJS(this)); - needsHTMLAttrs = true; - } else { - var attrsObjStr = this.generateAttrsDictionary(attrs[i]); - if (attrsObjStr !== null) - attrsArray.push(attrsObjStr); - } - } - } else if (hasToJS(attrs)) { - attrsArray.push(attrs.toJS(this)); - needsHTMLAttrs = true; - } else { - attrsArray.push(this.generateAttrsDictionary(attrs)); - } - } - var attrsStr = null; - if (attrsArray && attrsArray.length) { - if (attrsArray.length === 1 && ! needsHTMLAttrs) { - attrsStr = attrsArray[0]; - } else { - attrsStr = 'HTML.Attrs(' + attrsArray.join(', ') + ')'; - } - } - - var argStrs = []; - if (attrsStr !== null) - argStrs.push(attrsStr); - - if (children) { - for (var i = 0; i < children.length; i++) - argStrs.push(this.visit(children[i])); - } - - return tagSymbol + '(' + argStrs.join(', ') + ')'; - }, - generateAttrsDictionary: function (attrsDict) { - if (attrsDict.toJS && (typeof (attrsDict.toJS) === 'function')) { - // not an attrs dictionary, but something else! Like a template tag. - return attrsDict.toJS(this); - } - - var kvStrs = []; - for (var k in attrsDict) { - if (! HTML.isNully(attrsDict[k])) - kvStrs.push(toObjectLiteralKey(k) + ': ' + - this.visit(attrsDict[k])); - } - if (kvStrs.length) - return '{' + kvStrs.join(', ') + '}'; - return null; - } -}); -BlazeTools.ToJSVisitor = ToJSVisitor; - -BlazeTools.toJS = function (content) { - return (new ToJSVisitor).visit(content); -}; diff --git a/packages/blaze-tools/token_tests.js b/packages/blaze-tools/token_tests.js deleted file mode 100644 index 91aa8bd369..0000000000 --- a/packages/blaze-tools/token_tests.js +++ /dev/null @@ -1,78 +0,0 @@ -Tinytest.add("blaze-tools - token parsers", function (test) { - - var run = function (func, input, expected) { - var scanner = new HTMLTools.Scanner('z' + input); - // make sure the parse function respects `scanner.pos` - scanner.pos = 1; - var result = func(scanner); - if (expected === null) { - test.equal(scanner.pos, 1); - test.equal(result, null); - } else { - test.isTrue(scanner.isEOF()); - test.equal(result, expected); - } - }; - - var runValue = function (func, input, expectedValue) { - var expected; - if (expectedValue === null) - expected = null; - else - expected = { text: input, value: expectedValue }; - run(func, input, expected); - }; - - var parseNumber = BlazeTools.parseNumber; - var parseIdentifierName = BlazeTools.parseIdentifierName; - var parseExtendedIdentifierName = BlazeTools.parseExtendedIdentifierName; - var parseStringLiteral = BlazeTools.parseStringLiteral; - - runValue(parseNumber, "0", 0); - runValue(parseNumber, "-0", 0); - runValue(parseNumber, "-", null); - runValue(parseNumber, ".a", null); - runValue(parseNumber, ".1", 0.1); - runValue(parseNumber, "1.", 1); - runValue(parseNumber, "1.1", 1.1); - runValue(parseNumber, "0x", null); - runValue(parseNumber, "0xa", 10); - runValue(parseNumber, "-0xa", -10); - runValue(parseNumber, "1e+1", 10); - - _.each([parseIdentifierName, parseExtendedIdentifierName], function (f) { - run(f, "a", "a"); - run(f, "true", "true"); - run(f, "null", "null"); - run(f, "if", "if"); - run(f, "1", null); - run(f, "1a", null); - run(f, "+a", null); - run(f, "a1", "a1"); - run(f, "a1a", "a1a"); - run(f, "_a8f_f8d88_", "_a8f_f8d88_"); - }); - run(parseIdentifierName, "@index", null); - run(parseExtendedIdentifierName, "@index", "@index"); - run(parseExtendedIdentifierName, "@something", "@something"); - run(parseExtendedIdentifierName, "@", null); - - runValue(parseStringLiteral, '"a"', 'a'); - runValue(parseStringLiteral, '"\'"', "'"); - runValue(parseStringLiteral, '\'"\'', '"'); - runValue(parseStringLiteral, '"a\\\nb"', 'ab'); // line continuation - runValue(parseStringLiteral, '"a\u0062c"', 'abc'); - // Note: IE 8 doesn't correctly parse '\v' in JavaScript. - runValue(parseStringLiteral, '"\\0\\b\\f\\n\\r\\t\\v"', '\0\b\f\n\r\t\u000b'); - runValue(parseStringLiteral, '"\\x41"', 'A'); - runValue(parseStringLiteral, '"\\\\"', '\\'); - runValue(parseStringLiteral, '"\\\""', '\"'); - runValue(parseStringLiteral, '"\\\'"', '\''); - runValue(parseStringLiteral, "'\\\\'", '\\'); - runValue(parseStringLiteral, "'\\\"'", '\"'); - runValue(parseStringLiteral, "'\\\''", '\''); - - test.throws(function () { - run(parseStringLiteral, "'this is my string"); - }, /Unterminated string literal/); -}); diff --git a/packages/blaze-tools/tokens.js b/packages/blaze-tools/tokens.js deleted file mode 100644 index 441d070fb4..0000000000 --- a/packages/blaze-tools/tokens.js +++ /dev/null @@ -1,193 +0,0 @@ - -// Adapted from source code of http://xregexp.com/plugins/#unicode -var unicodeCategories = { - Ll: "0061-007A00B500DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F05210523052505270561-05871D00-1D2B1D6B-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7B2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2CF32D00-2D252D272D2DA641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA661A663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CA78EA791A793A7A1A7A3A7A5A7A7A7A9A7FAFB00-FB06FB13-FB17FF41-FF5A", - Lm: "02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D6A1D781D9B-1DBF2071207F2090-209C2C7C2C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A7F8A7F9A9CFAA70AADDAAF3AAF4FF70FF9EFF9F", - Lo: "00AA00BA01BB01C0-01C3029405D0-05EA05F0-05F20620-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150840-085808A008A2-08AC0904-0939093D09500958-09610972-09770979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10CF10CF20D05-0D0C0D0E-0D100D12-0D3A0D3D0D4E0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC-0EDF0F000F40-0F470F49-0F6C0F88-0F8C1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA10FD-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1BBA-1BE51C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF11CF51CF62135-21382D30-2D672D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31BA31F0-31FF3400-4DB54E00-9FCCA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCAAE0-AAEAAAF2AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC", - Lt: "01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC", - Lu: "0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E05200522052405260531-055610A0-10C510C710CD1E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CED2CF2A640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA660A662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BA78DA790A792A7A0A7A2A7A4A7A6A7A8A7AAFF21-FF3A", - Mc: "0903093B093E-09400949-094C094E094F0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1BAC1BAD1BE71BEA-1BEC1BEE1BF21BF31C24-1C2B1C341C351CE11CF21CF3302E302FA823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BAAEBAAEEAAEFAAF5ABE3ABE4ABE6ABE7ABE9ABEAABEC", - Mn: "0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065F067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0859-085B08E4-08FE0900-0902093A093C0941-0948094D0951-095709620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F8D-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135D-135F1712-17141732-1734175217531772177317B417B517B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91BAB1BE61BE81BE91BED1BEF-1BF11C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1CF41DC0-1DE61DFC-1DFF20D0-20DC20E120E5-20F02CEF-2CF12D7F2DE0-2DFF302A-302D3099309AA66FA674-A67DA69FA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1AAECAAEDAAF6ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26", - Nd: "0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19D91A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19", - Nl: "16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF", - Pc: "005F203F20402054FE33FE34FE4D-FE4FFF3F" -}; - -var unicodeClass = function (abbrev) { - return '[' + - unicodeCategories[abbrev].replace(/[0-9A-F]{4}/ig, "\\u$&") + ']'; -}; - -// See ECMA-262 spec, 3rd edition, Section 7.6 -// Match one or more characters that can start an identifier. -// This is IdentifierStart+. -var rIdentifierPrefix = new RegExp( - "^([a-zA-Z$_]+|\\\\u[0-9a-fA-F]{4}|" + - [unicodeClass('Lu'), unicodeClass('Ll'), unicodeClass('Lt'), - unicodeClass('Lm'), unicodeClass('Lo'), unicodeClass('Nl')].join('|') + - ")+"); -// Match one or more characters that can continue an identifier. -// This is (IdentifierPart and not IdentifierStart)+. -// To match a full identifier, match rIdentifierPrefix, then -// match rIdentifierMiddle followed by rIdentifierPrefix until they both fail. -var rIdentifierMiddle = new RegExp( - "^([0-9]|" + [unicodeClass('Mn'), unicodeClass('Mc'), unicodeClass('Nd'), - unicodeClass('Pc')].join('|') + ")+"); - - -// See ECMA-262 spec, 3rd edition, Section 7.8.3 -var rHexLiteral = /^0[xX][0-9a-fA-F]+(?!\w)/; -var rDecLiteral = - /^(((0|[1-9][0-9]*)(\.[0-9]*)?)|\.[0-9]+)([Ee][+-]?[0-9]+)?(?!\w)/; - -// Section 7.8.4 -var rStringQuote = /^["']/; -// Match one or more characters besides quotes, backslashes, or line ends -var rStringMiddle = /^(?=.)[^"'\\]+?((?!.)|(?=["'\\]))/; -// Match one escape sequence, including the backslash. -var rEscapeSequence = - /^\\(['"\\bfnrtv]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|(?=.)[^ux0-9])/; -// Match one ES5 line continuation -var rLineContinuation = - /^\\(\r\n|[\u000A\u000D\u2028\u2029])/; - - -BlazeTools.parseNumber = function (scanner) { - var startPos = scanner.pos; - - var isNegative = false; - if (scanner.peek() === '-') { - scanner.pos++; - isNegative = true; - } - // Note that we allow `"-0xa"`, unlike `Number(...)`. - - var rest = scanner.rest(); - var match = rDecLiteral.exec(rest) || rHexLiteral.exec(rest); - if (! match) { - scanner.pos = startPos; - return null; - } - var matchText = match[0]; - scanner.pos += matchText.length; - - var text = (isNegative ? '-' : '') + matchText; - var value = Number(matchText); - value = (isNegative ? -value : value); - return { text: text, value: value }; -}; - -BlazeTools.parseIdentifierName = function (scanner) { - var startPos = scanner.pos; - var rest = scanner.rest(); - var match = rIdentifierPrefix.exec(rest); - if (! match) - return null; - scanner.pos += match[0].length; - rest = scanner.rest(); - var foundMore = true; - - while (foundMore) { - foundMore = false; - - match = rIdentifierMiddle.exec(rest); - if (match) { - foundMore = true; - scanner.pos += match[0].length; - rest = scanner.rest(); - } - - match = rIdentifierPrefix.exec(rest); - if (match) { - foundMore = true; - scanner.pos += match[0].length; - rest = scanner.rest(); - } - } - - return scanner.input.substring(startPos, scanner.pos); -}; - -BlazeTools.parseExtendedIdentifierName = function (scanner) { - // parse an identifier name optionally preceded by '@' - if (scanner.peek() === '@') { - scanner.pos++; - var afterAt = BlazeTools.parseIdentifierName(scanner); - if (afterAt) { - return '@' + afterAt; - } else { - scanner.pos--; - return null; - } - } else { - return BlazeTools.parseIdentifierName(scanner); - } -}; - -BlazeTools.parseStringLiteral = function (scanner) { - var startPos = scanner.pos; - var rest = scanner.rest(); - var match = rStringQuote.exec(rest); - if (! match) - return null; - - var quote = match[0]; - scanner.pos++; - rest = scanner.rest(); - - var jsonLiteral = '"'; - - while (match) { - match = rStringMiddle.exec(rest); - if (match) { - jsonLiteral += match[0]; - } else { - match = rEscapeSequence.exec(rest); - if (match) { - var esc = match[0]; - // Convert all string escapes to JSON-compatible string escapes, so we - // can use JSON.parse for some of the work. JSON strings are not the - // same as JS strings. They don't support `\0`, `\v`, `\'`, or hex - // escapes. - if (esc === '\\0') - jsonLiteral += '\\u0000'; - else if (esc === '\\v') - // Note: IE 8 doesn't correctly parse '\v' in JavaScript. - jsonLiteral += '\\u000b'; - else if (esc.charAt(1) === 'x') - jsonLiteral += '\\u00' + esc.slice(2); - else if (esc === '\\\'') - jsonLiteral += "'"; - else - jsonLiteral += esc; - } else { - match = rLineContinuation.exec(rest); - if (! match) { - match = rStringQuote.exec(rest); - if (match) { - var c = match[0]; - if (c !== quote) { - if (c === '"') - jsonLiteral += '\\'; - jsonLiteral += c; - } - } - } - } - } - if (match) { - scanner.pos += match[0].length; - rest = scanner.rest(); - if (match[0] === quote) - break; - } - } - - if (! match || match[0] !== quote) - scanner.fatal("Unterminated string literal"); - - jsonLiteral += '"'; - var text = scanner.input.substring(startPos, scanner.pos); - var value = JSON.parse(jsonLiteral); - return { text: text, value: value }; -}; diff --git a/packages/blaze/.gitignore b/packages/blaze/.gitignore deleted file mode 100644 index 677a6fc263..0000000000 --- a/packages/blaze/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.build* diff --git a/packages/blaze/README.md b/packages/blaze/README.md deleted file mode 100644 index 81d8298630..0000000000 --- a/packages/blaze/README.md +++ /dev/null @@ -1,318 +0,0 @@ -# Blaze - -Blaze is a powerful library for creating user interfaces by writing -reactive HTML templates. Compared to using a combination of -traditional templates and jQuery, Blaze eliminates the need for all -the "update logic" in your app that listens for data changes and -manipulates the DOM. Instead, familiar template directives like - -`{{#if}}` and `{{#each}}` integrate with -[Tracker's](https://meteor.com/tracker) "transparent reactivity" and -[Minimongo's](https://meteor.com/mini-databases) database cursors so -that the DOM updates automatically. - -Read more on the Blaze [project page](http://www.meteor.com/blaze). - -## Details - -Blaze has two major parts: - -* A template compiler that compiles template files into JavaScript - code that runs against the Blaze runtime library. Moreover, Blaze - provides a compiler toolchain (think LLVM) that can be used to - support arbitrary template syntaxes. The flagship template syntax - is Spacebars, a variant of Handlebars, but a community alternative - based on Jade is already in use by many apps. - -* A reactive DOM engine that builds and manages the DOM at runtime, - invoked via templates or directly from the app, which features - reactively updating regions, lists, and attributes; event - delegation; and many callbacks and hooks to aid the app developer. - -Blaze is sometimes compared to frameworks like React, Angular, Ember, -Polymer, Knockout, and others by virtue of its advanced templating -system. What sets Blaze apart is a relentless focus on the developer -experience, using templating, transparent reactivity, and -interoperability with existing libraries to create a gentle learning -curve while enabling you to build world-class apps. - -## Examples - -Here are two Spacebars templates from an example app called -"Leaderboard" which displays a sorted list of top players and their -scores: - -```html - - - -``` - -The template tags `{{name}}` and `{{score}}` refer to properties of -the data context (the current player), while `players` and `selected` -refer to helper functions. Helper functions and event handlers are defined -in JavaScript: - -```javascript -Template.leaderboard.helpers({ - players: function () { - // Perform a reactive database query against minimongo - return Players.find({}, { sort: { score: -1, name: 1 } }); - } -}); - -Template.player.events({ - 'click': function () { - // click on a player to select it - Session.set("selectedPlayer", this._id); - } -}); - -Template.player.helpers({ - selected: function () { - return Session.equals("selectedPlayer", this._id) ? "selected" : ''; - } -}); -``` - -No additional UI code is necessary to ensure that the list of players -stays up-to-date, or that the "selected" class is added and removed -from the LI elements as appropriate when the user clicks on a player. - -Thanks to a powerful template language, it doesn't take much ceremony -to write a loop, include another template, or bind an attribute (or -part of an attribute). And thanks to Tracker's transparent -reactivity, there's no ceremony around depending on reactive data -sources like the database or Session; it just happens when you read -the value, and when the value changes, the DOM will be updated in a -fine-grained way. - -# Principles - -## Gentle Learning Curve - -To get started with Blaze, you don't have to learn a lot of concepts -or terminology. As web developers, we are already students of HTML, -CSS, and JavaScript, which are complex technologies described in thick -books. Blaze lets you apply your existing knowledge in exciting new -ways without having to read another book first. - -Many factors go into making Blaze easy to pick up and use, including -the other principles below. In general, we prefer APIs that lead to -simple and obvious-looking application code, and we recognize that -developers have limited time and energy to learn new and unfamiliar -terms and syntaxes. - -It may sound obvious to "keep it simple" and prioritize the developer -experience when creating a system for reactive HTML, but it's also -challenging, and we think it's not done often enough! We use feedback -from the Meteor community to ensure that Blaze's features stay simple, -understandable, and useful. - -## Transparent Reactivity - -Under the hood, Blaze uses the [Tracker](https://meteor.com/tracker) -library to automatically keep track of when to recalculate each -template helper. If a helper reads a value from the client-side -database, for example, the helper will automatically be recalculated -when the value changes. - -What this means for the developer is simple. You don't have to -explicitly declare when to update the DOM, or even perform any -explicit "data-binding." You don't have to know how Tracker works, or -even exactly what "reactivity" means, to benefit. The result is less -thinking and less typing than other approaches. - -## Clean Templates - -Blaze embraces popular template syntaxes such as Handlebars and Jade -which are clean, readable, and familiar to developers coming from -other frameworks. - -A good template language should clearly distinguish the special -"template directives" (often enclosed in curly braces) from the HTML, -and it should not obscure the structure of the resulting HTML. These -properties make templating an easy concept to learn after static HTML -(or alongside it), and make templates easy to read, easy to style with -CSS, and easy to relate to the DOM. - -In contrast, some newer frameworks try to remake templates as just -HTML (Angular, Polymer) or replace them with just JavaScript (React). -These approaches tend to obscure either the structure of the template, -or what is a real DOM element and what is not, or both. In addition, -since templates are generally precompiled anyway as a best practice, -it's really not important that raw template source code be -browser-parsable. Meanwhile, the developer experience of reading, -writing, and maintaining templates is hugely important. - -## Plugin Interoperability - -Web developers often share snippets of HTML, JavaScript, and CSS, or -publish them as libraries, widgets, or jQuery plugins. They want to -embed videos, maps, and other third-party content. - -Blaze doesn't assume it owns the whole DOM, and it tries to make as -few assumptions as possible about the DOM outside of its updates. -It hooks into jQuery's clean-up routines to prevent memory leaks, -and it preserves classes, attributes, and styles added to elements -by jQuery or any third-party library. - -While it's certainly possible for Blaze and jQuery to step on each -other's toes if you aren't careful, there are established patterns for -keeping the peace, and Meteor users rightfully expect to be able to -use the various widgets and enhancements cooked up by the broader web -community in their apps. - -# Comparisons to other libraries - -Compared to Backbone and other libraries that simply re-render -templates, Blaze does much less re-rendering and doesn't suffer from -the dreaded "nested view" problem, which is when two templates can't -be updated independently of each other because one is nested inside -the other. In addition, Blaze automatically determines when -re-rendering must occur, using Tracker. - -Compared to Ember, Blaze offers finer-grained, automatic DOM updates. -Because Blaze uses Tracker's transparent reactivity, you don't have to -perform explicit "data-binding" to get data into your template, or -declare the data dependencies of each template helper. - -Compared to Angular and Polymer, Blaze has a gentler learning curve, -simpler concepts, and nicer template syntax that cleanly separates -template directives and HTML. Also, Blaze is targeted at today's -browsers and not designed around a hypothetical "browser of the -future." - -Compared to React, Blaze emphasizes HTML templates rather than -JavaScript component classes. Templates are more approachable than -JavaScript code and easier to read, write, and style with CSS. -Instead of using Tracker, React relies on a combination of explicit -"setState" calls and data-model diffing in order to achieve efficient -rendering. - -# Future Work - -### Components - -Blaze will get better patterns for creating reusable UI components. -Templates already serve as reusable components, to a point. -Improvements will focus on: - -* Argument-handling -* Local reactive state -* "Methods" that are callable from other components and have side - effects, versus the current "helpers" which are called from the - template language and are "pure" -* Scoping and the lookup chain -* Inheritance and configuration - -### Forms - -Most applications have a lot of forms, where input fields and other -widgets are used to enter data, which must then be validated and -turned into database changes. Server-side frameworks like Rails and -Django have well-honed patterns for this, but client-side frameworks -are typically more lacking, perhaps because they are more estranged -from the database. - -Meteor developers have already found ways and built packages to deal -with forms and validation, but we think there's a great opportunity to -make this part of the core, out-of-the-box Meteor experience. - -### Mobile and Animation - -Blaze will cater to the needs of the mobile web, including enhanced -performance and patterns for touch and other mobile interaction. - -We'll also improve the ease with which developers can integrate -animated transitions into their apps. - -### JavaScript Expressions in Templates - -We plan to support JavaScript expressions in templates. This will -make templates more expressive, and it will further shorten -application code by eliminating the need for a certain class of -one-line helpers. - -The usual argument against allowing JavaScript expressions in a -template language is one of "separation of concerns" -- separating -business logic from presentation, so that the business logic may be -better organized, maintained, and tested independently. Meanwhile, -even "logicless" template languages often include some concessions in -the form of microsyntax for filtering, querying, and transforming data -before using it. This special syntax (and its extension mechanisms) -must then be learned. - -While keeping business logic out of templates is indeed good policy, -there is a large class of "presentation logic" that is not really -separable from the concerns of templates and HTML, such as the code to -calculate styles and classes to apply to HTML elements or to massage -data records into a better form for templating purposes. In many -cases where this code is short, it may be more convenient or more -readable to embed the code in the template, and it's certainly better -than evolving the template syntax in a direction that diverges from -JavaScript. - -Because templates are already precompiled to JavaScript code, there is -nothing fundamentally difficult or inelegant about allowing a large -subset of JavaScript to be used within templates (see e.g. the project -Ractive.js). - -### Other Template Enhancements - -Source maps for debugging templates. Imagine seeing your template -code in the browser's debugger! Pretty slick. - -True lexical scoping. - -Better support for pluggable template syntax (e.g. Jade-like -templates). There is already a Jade package in use, but we should -learn from it and clarify the abstraction boundary that authors of -template syntaxes are programming against. - -### Pluggable Backends (don't require jQuery) - -While Blaze currently requires jQuery, it is architected to run -against other "DOM backends" using a common adaptor interface. You -should be able to use Zepto, or some very small shim if browser -compatibility is not a big deal for your application for some reason. -At the moment, no such adaptors besides the jQuery one have been -written. - -The Blaze team experimented with dropping jQuery and talking directly -to "modern browsers," but it turns out there is about 5-10K of code at -the heart of jQuery that you can't throw out even if you don't care -about old browsers or supporting jQuery's app-facing API, which is -required just to bring browsers up to the modest expectations of web -developers. - -### Better Stand-alone Support - -Blaze will get better support for using it outside of Meteor, such as -regular stand-alone builds. - -# Resources - -* [Templates API](http://docs.meteor.com/#templates_api) -* [Blaze API](http://docs.meteor.com/#blaze) -* [Spacebars syntax](https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md) - -# Packages - -* blaze -* blaze-tools -* html-tools -* htmljs -* spacebars -* spacebars-compiler diff --git a/packages/blaze/attrs.js b/packages/blaze/attrs.js deleted file mode 100644 index 427f9cf8ec..0000000000 --- a/packages/blaze/attrs.js +++ /dev/null @@ -1,365 +0,0 @@ -var jsUrlsAllowed = false; -Blaze._allowJavascriptUrls = function () { - jsUrlsAllowed = true; -}; -Blaze._javascriptUrlsAllowed = function () { - return jsUrlsAllowed; -}; - -// An AttributeHandler object is responsible for updating a particular attribute -// of a particular element. AttributeHandler subclasses implement -// browser-specific logic for dealing with particular attributes across -// different browsers. -// -// To define a new type of AttributeHandler, use -// `var FooHandler = AttributeHandler.extend({ update: function ... })` -// where the `update` function takes arguments `(element, oldValue, value)`. -// The `element` argument is always the same between calls to `update` on -// the same instance. `oldValue` and `value` are each either `null` or -// a Unicode string of the type that might be passed to the value argument -// of `setAttribute` (i.e. not an HTML string with character references). -// When an AttributeHandler is installed, an initial call to `update` is -// always made with `oldValue = null`. The `update` method can access -// `this.name` if the AttributeHandler class is a generic one that applies -// to multiple attribute names. -// -// AttributeHandlers can store custom properties on `this`, as long as they -// don't use the names `element`, `name`, `value`, and `oldValue`. -// -// AttributeHandlers can't influence how attributes appear in rendered HTML, -// only how they are updated after materialization as DOM. - -AttributeHandler = function (name, value) { - this.name = name; - this.value = value; -}; -Blaze._AttributeHandler = AttributeHandler; - -AttributeHandler.prototype.update = function (element, oldValue, value) { - if (value === null) { - if (oldValue !== null) - element.removeAttribute(this.name); - } else { - element.setAttribute(this.name, value); - } -}; - -AttributeHandler.extend = function (options) { - var curType = this; - var subType = function AttributeHandlerSubtype(/*arguments*/) { - AttributeHandler.apply(this, arguments); - }; - subType.prototype = new curType; - subType.extend = curType.extend; - if (options) - _.extend(subType.prototype, options); - return subType; -}; - -/// Apply the diff between the attributes of "oldValue" and "value" to "element." -// -// Each subclass must implement a parseValue method which takes a string -// as an input and returns a dict of attributes. The keys of the dict -// are unique identifiers (ie. css properties in the case of styles), and the -// values are the entire attribute which will be injected into the element. -// -// Extended below to support classes, SVG elements and styles. - -var DiffingAttributeHandler = AttributeHandler.extend({ - update: function (element, oldValue, value) { - if (!this.getCurrentValue || !this.setValue || !this.parseValue) - throw new Error("Missing methods in subclass of 'DiffingAttributeHandler'"); - - var oldAttrsMap = oldValue ? this.parseValue(oldValue) : {}; - var newAttrsMap = value ? this.parseValue(value) : {}; - - // the current attributes on the element, which we will mutate. - - var attrString = this.getCurrentValue(element); - var attrsMap = attrString ? this.parseValue(attrString) : {}; - - _.each(_.keys(oldAttrsMap), function (t) { - if (! (t in newAttrsMap)) - delete attrsMap[t]; - }); - - _.each(_.keys(newAttrsMap), function (t) { - attrsMap[t] = newAttrsMap[t]; - }); - - this.setValue(element, _.values(attrsMap).join(' ')); - } -}); - -var ClassHandler = DiffingAttributeHandler.extend({ - // @param rawValue {String} - getCurrentValue: function (element) { - return element.className; - }, - setValue: function (element, className) { - element.className = className; - }, - parseValue: function (attrString) { - var tokens = {}; - - _.each(attrString.split(' '), function(token) { - if (token) - tokens[token] = token; - }); - return tokens; - } -}); - -var SVGClassHandler = ClassHandler.extend({ - getCurrentValue: function (element) { - return element.className.baseVal; - }, - setValue: function (element, className) { - element.setAttribute('class', className); - } -}); - -var StyleHandler = DiffingAttributeHandler.extend({ - getCurrentValue: function (element) { - return element.getAttribute('style'); - }, - setValue: function (element, style) { - if (style === '') { - element.removeAttribute('style'); - } else { - element.setAttribute('style', style); - } - }, - - // Parse a string to produce a map from property to attribute string. - // - // Example: - // "color:red; foo:12px" produces a token {color: "color:red", foo:"foo:12px"} - parseValue: function (attrString) { - var tokens = {}; - - // Regex for parsing a css attribute declaration, taken from css-parse: - // https://github.com/reworkcss/css-parse/blob/7cef3658d0bba872cde05a85339034b187cb3397/index.js#L219 - var regex = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*(?:\'(?:\\\'|.)*?\'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+[;\s]*/g; - var match = regex.exec(attrString); - while (match) { - // match[0] = entire matching string - // match[1] = css property - // Prefix the token to prevent conflicts with existing properties. - - // XXX No `String.trim` on Safari 4. Swap out $.trim if we want to - // remove strong dep on jquery. - tokens[' ' + match[1]] = match[0].trim ? - match[0].trim() : $.trim(match[0]); - - match = regex.exec(attrString); - } - - return tokens; - } -}); - -var BooleanHandler = AttributeHandler.extend({ - update: function (element, oldValue, value) { - var name = this.name; - if (value == null) { - if (oldValue != null) - element[name] = false; - } else { - element[name] = true; - } - } -}); - -var DOMPropertyHandler = AttributeHandler.extend({ - update: function (element, oldValue, value) { - var name = this.name; - if (value !== element[name]) - element[name] = value; - } -}); - -// attributes of the type 'xlink:something' should be set using -// the correct namespace in order to work -var XlinkHandler = AttributeHandler.extend({ - update: function(element, oldValue, value) { - var NS = 'http://www.w3.org/1999/xlink'; - if (value === null) { - if (oldValue !== null) - element.removeAttributeNS(NS, this.name); - } else { - element.setAttributeNS(NS, this.name, this.value); - } - } -}); - -// cross-browser version of `instanceof SVGElement` -var isSVGElement = function (elem) { - return 'ownerSVGElement' in elem; -}; - -var isUrlAttribute = function (tagName, attrName) { - // Compiled from http://www.w3.org/TR/REC-html40/index/attributes.html - // and - // http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1 - var urlAttrs = { - FORM: ['action'], - BODY: ['background'], - BLOCKQUOTE: ['cite'], - Q: ['cite'], - DEL: ['cite'], - INS: ['cite'], - OBJECT: ['classid', 'codebase', 'data', 'usemap'], - APPLET: ['codebase'], - A: ['href'], - AREA: ['href'], - LINK: ['href'], - BASE: ['href'], - IMG: ['longdesc', 'src', 'usemap'], - FRAME: ['longdesc', 'src'], - IFRAME: ['longdesc', 'src'], - HEAD: ['profile'], - SCRIPT: ['src'], - INPUT: ['src', 'usemap', 'formaction'], - BUTTON: ['formaction'], - BASE: ['href'], - MENUITEM: ['icon'], - HTML: ['manifest'], - VIDEO: ['poster'] - }; - - if (attrName === 'itemid') { - return true; - } - - var urlAttrNames = urlAttrs[tagName] || []; - return _.contains(urlAttrNames, attrName); -}; - -// To get the protocol for a URL, we let the browser normalize it for -// us, by setting it as the href for an anchor tag and then reading out -// the 'protocol' property. -if (Meteor.isClient) { - var anchorForNormalization = document.createElement('A'); -} - -var getUrlProtocol = function (url) { - if (Meteor.isClient) { - anchorForNormalization.href = url; - return (anchorForNormalization.protocol || "").toLowerCase(); - } else { - throw new Error('getUrlProtocol not implemented on the server'); - } -}; - -// UrlHandler is an attribute handler for all HTML attributes that take -// URL values. It disallows javascript: URLs, unless -// Blaze._allowJavascriptUrls() has been called. To detect javascript: -// urls, we set the attribute on a dummy anchor element and then read -// out the 'protocol' property of the attribute. -var origUpdate = AttributeHandler.prototype.update; -var UrlHandler = AttributeHandler.extend({ - update: function (element, oldValue, value) { - var self = this; - var args = arguments; - - if (Blaze._javascriptUrlsAllowed()) { - origUpdate.apply(self, args); - } else { - var isJavascriptProtocol = (getUrlProtocol(value) === "javascript:"); - var isVBScriptProtocol = (getUrlProtocol(value) === "vbscript:"); - if (isJavascriptProtocol || isVBScriptProtocol) { - Blaze._warn("URLs that use the 'javascript:' or 'vbscript:' protocol are not " + - "allowed in URL attribute values. " + - "Call Blaze._allowJavascriptUrls() " + - "to enable them."); - origUpdate.apply(self, [element, oldValue, null]); - } else { - origUpdate.apply(self, args); - } - } - } -}); - -// XXX make it possible for users to register attribute handlers! -makeAttributeHandler = function (elem, name, value) { - // generally, use setAttribute but certain attributes need to be set - // by directly setting a JavaScript property on the DOM element. - if (name === 'class') { - if (isSVGElement(elem)) { - return new SVGClassHandler(name, value); - } else { - return new ClassHandler(name, value); - } - } else if (name === 'style') { - return new StyleHandler(name, value); - } else if ((elem.tagName === 'OPTION' && name === 'selected') || - (elem.tagName === 'INPUT' && name === 'checked')) { - return new BooleanHandler(name, value); - } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT') - && name === 'value') { - // internally, TEXTAREAs tracks their value in the 'value' - // attribute just like INPUTs. - return new DOMPropertyHandler(name, value); - } else if (name.substring(0,6) === 'xlink:') { - return new XlinkHandler(name.substring(6), value); - } else if (isUrlAttribute(elem.tagName, name)) { - return new UrlHandler(name, value); - } else { - return new AttributeHandler(name, value); - } - - // XXX will need one for 'style' on IE, though modern browsers - // seem to handle setAttribute ok. -}; - - -ElementAttributesUpdater = function (elem) { - this.elem = elem; - this.handlers = {}; -}; - -// Update attributes on `elem` to the dictionary `attrs`, whose -// values are strings. -ElementAttributesUpdater.prototype.update = function(newAttrs) { - var elem = this.elem; - var handlers = this.handlers; - - for (var k in handlers) { - if (! _.has(newAttrs, k)) { - // remove attributes (and handlers) for attribute names - // that don't exist as keys of `newAttrs` and so won't - // be visited when traversing it. (Attributes that - // exist in the `newAttrs` object but are `null` - // are handled later.) - var handler = handlers[k]; - var oldValue = handler.value; - handler.value = null; - handler.update(elem, oldValue, null); - delete handlers[k]; - } - } - - for (var k in newAttrs) { - var handler = null; - var oldValue; - var value = newAttrs[k]; - if (! _.has(handlers, k)) { - if (value !== null) { - // make new handler - handler = makeAttributeHandler(elem, k, value); - handlers[k] = handler; - oldValue = null; - } - } else { - handler = handlers[k]; - oldValue = handler.value; - } - if (oldValue !== value) { - handler.value = value; - handler.update(elem, oldValue, value); - if (value === null) - delete handlers[k]; - } - } -}; diff --git a/packages/blaze/backcompat.js b/packages/blaze/backcompat.js deleted file mode 100644 index d8c5d509d8..0000000000 --- a/packages/blaze/backcompat.js +++ /dev/null @@ -1,18 +0,0 @@ -UI = Blaze; - -Blaze.ReactiveVar = ReactiveVar; -UI._templateInstance = Blaze.Template.instance; - -Handlebars = {}; -Handlebars.registerHelper = Blaze.registerHelper; - -Handlebars._escape = Blaze._escape; - -// Return these from {{...}} helpers to achieve the same as returning -// strings from {{{...}}} helpers -Handlebars.SafeString = function(string) { - this.string = string; -}; -Handlebars.SafeString.prototype.toString = function() { - return this.string.toString(); -}; diff --git a/packages/blaze/builtins.js b/packages/blaze/builtins.js deleted file mode 100644 index 4d883bcd97..0000000000 --- a/packages/blaze/builtins.js +++ /dev/null @@ -1,354 +0,0 @@ -Blaze._calculateCondition = function (cond) { - if (cond instanceof Array && cond.length === 0) - cond = false; - return !! cond; -}; - -/** - * @summary Constructs a View that renders content with a data context. - * @locus Client - * @param {Object|Function} data An object to use as the data context, or a function returning such an object. If a function is provided, it will be reactively re-run. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). - */ -Blaze.With = function (data, contentFunc) { - var view = Blaze.View('with', contentFunc); - - view.dataVar = new ReactiveVar; - - view.onViewCreated(function () { - if (typeof data === 'function') { - // `data` is a reactive function - view.autorun(function () { - view.dataVar.set(data()); - }, view.parentView, 'setData'); - } else { - view.dataVar.set(data); - } - }); - - return view; -}; - -/** - * Attaches bindings to the instantiated view. - * @param {Object} bindings A dictionary of bindings, each binding name - * corresponds to a value or a function that will be reactively re-run. - * @param {View} view The target. - */ -Blaze._attachBindingsToView = function (bindings, view) { - view.onViewCreated(function () { - _.each(bindings, function (binding, name) { - view._scopeBindings[name] = new ReactiveVar; - if (typeof binding === 'function') { - view.autorun(function () { - view._scopeBindings[name].set(binding()); - }, view.parentView); - } else { - view._scopeBindings[name].set(binding); - } - }); - }); -}; - -/** - * @summary Constructs a View setting the local lexical scope in the block. - * @param {Function} bindings Dictionary mapping names of bindings to - * values or computations to reactively re-run. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). - */ -Blaze.Let = function (bindings, contentFunc) { - var view = Blaze.View('let', contentFunc); - Blaze._attachBindingsToView(bindings, view); - - return view; -}; - -/** - * @summary Constructs a View that renders content conditionally. - * @locus Client - * @param {Function} conditionFunc A function to reactively re-run. Whether the result is truthy or falsy determines whether `contentFunc` or `elseFunc` is shown. An empty array is considered falsy. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). - * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content). If no `elseFunc` is supplied, no content is shown in the "else" case. - */ -Blaze.If = function (conditionFunc, contentFunc, elseFunc, _not) { - var conditionVar = new ReactiveVar; - - var view = Blaze.View(_not ? 'unless' : 'if', function () { - return conditionVar.get() ? contentFunc() : - (elseFunc ? elseFunc() : null); - }); - view.__conditionVar = conditionVar; - view.onViewCreated(function () { - this.autorun(function () { - var cond = Blaze._calculateCondition(conditionFunc()); - conditionVar.set(_not ? (! cond) : cond); - }, this.parentView, 'condition'); - }); - - return view; -}; - -/** - * @summary An inverted [`Blaze.If`](#blaze_if). - * @locus Client - * @param {Function} conditionFunc A function to reactively re-run. If the result is falsy, `contentFunc` is shown, otherwise `elseFunc` is shown. An empty array is considered falsy. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). - * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content). If no `elseFunc` is supplied, no content is shown in the "else" case. - */ -Blaze.Unless = function (conditionFunc, contentFunc, elseFunc) { - return Blaze.If(conditionFunc, contentFunc, elseFunc, true /*_not*/); -}; - -/** - * @summary Constructs a View that renders `contentFunc` for each item in a sequence. - * @locus Client - * @param {Function} argFunc A function to reactively re-run. The function can - * return one of two options: - * - * 1. An object with two fields: '_variable' and '_sequence'. Each iterates over - * '_sequence', it may be a Cursor, an array, null, or undefined. Inside the - * Each body you will be able to get the current item from the sequence using - * the name specified in the '_variable' field. - * - * 2. Just a sequence (Cursor, array, null, or undefined) not wrapped into an - * object. Inside the Each body, the current item will be set as the data - * context. - * @param {Function} contentFunc A Function that returns [*renderable - * content*](#renderable_content). - * @param {Function} [elseFunc] A Function that returns [*renderable - * content*](#renderable_content) to display in the case when there are no items - * in the sequence. - */ -Blaze.Each = function (argFunc, contentFunc, elseFunc) { - var eachView = Blaze.View('each', function () { - var subviews = this.initialSubviews; - this.initialSubviews = null; - if (this._isCreatedForExpansion) { - this.expandedValueDep = new Tracker.Dependency; - this.expandedValueDep.depend(); - } - return subviews; - }); - eachView.initialSubviews = []; - eachView.numItems = 0; - eachView.inElseMode = false; - eachView.stopHandle = null; - eachView.contentFunc = contentFunc; - eachView.elseFunc = elseFunc; - eachView.argVar = new ReactiveVar; - eachView.variableName = null; - - // update the @index value in the scope of all subviews in the range - var updateIndices = function (from, to) { - if (to === undefined) { - to = eachView.numItems - 1; - } - - for (var i = from; i <= to; i++) { - var view = eachView._domrange.members[i].view; - view._scopeBindings['@index'].set(i); - } - }; - - eachView.onViewCreated(function () { - // We evaluate argFunc in an autorun to make sure - // Blaze.currentView is always set when it runs (rather than - // passing argFunc straight to ObserveSequence). - eachView.autorun(function () { - // argFunc can return either a sequence as is or a wrapper object with a - // _sequence and _variable fields set. - var arg = argFunc(); - if (_.isObject(arg) && _.has(arg, '_sequence')) { - eachView.variableName = arg._variable || null; - arg = arg._sequence; - } - - eachView.argVar.set(arg); - }, eachView.parentView, 'collection'); - - eachView.stopHandle = ObserveSequence.observe(function () { - return eachView.argVar.get(); - }, { - addedAt: function (id, item, index) { - Tracker.nonreactive(function () { - var newItemView; - if (eachView.variableName) { - // new-style #each (as in {{#each item in items}}) - // doesn't create a new data context - newItemView = Blaze.View('item', eachView.contentFunc); - } else { - newItemView = Blaze.With(item, eachView.contentFunc); - } - - eachView.numItems++; - - var bindings = {}; - bindings['@index'] = index; - if (eachView.variableName) { - bindings[eachView.variableName] = item; - } - Blaze._attachBindingsToView(bindings, newItemView); - - if (eachView.expandedValueDep) { - eachView.expandedValueDep.changed(); - } else if (eachView._domrange) { - if (eachView.inElseMode) { - eachView._domrange.removeMember(0); - eachView.inElseMode = false; - } - - var range = Blaze._materializeView(newItemView, eachView); - eachView._domrange.addMember(range, index); - updateIndices(index); - } else { - eachView.initialSubviews.splice(index, 0, newItemView); - } - }); - }, - removedAt: function (id, item, index) { - Tracker.nonreactive(function () { - eachView.numItems--; - if (eachView.expandedValueDep) { - eachView.expandedValueDep.changed(); - } else if (eachView._domrange) { - eachView._domrange.removeMember(index); - updateIndices(index); - if (eachView.elseFunc && eachView.numItems === 0) { - eachView.inElseMode = true; - eachView._domrange.addMember( - Blaze._materializeView( - Blaze.View('each_else',eachView.elseFunc), - eachView), 0); - } - } else { - eachView.initialSubviews.splice(index, 1); - } - }); - }, - changedAt: function (id, newItem, oldItem, index) { - Tracker.nonreactive(function () { - if (eachView.expandedValueDep) { - eachView.expandedValueDep.changed(); - } else { - var itemView; - if (eachView._domrange) { - itemView = eachView._domrange.getMember(index).view; - } else { - itemView = eachView.initialSubviews[index]; - } - if (eachView.variableName) { - itemView._scopeBindings[eachView.variableName].set(newItem); - } else { - itemView.dataVar.set(newItem); - } - } - }); - }, - movedTo: function (id, item, fromIndex, toIndex) { - Tracker.nonreactive(function () { - if (eachView.expandedValueDep) { - eachView.expandedValueDep.changed(); - } else if (eachView._domrange) { - eachView._domrange.moveMember(fromIndex, toIndex); - updateIndices( - Math.min(fromIndex, toIndex), Math.max(fromIndex, toIndex)); - } else { - var subviews = eachView.initialSubviews; - var itemView = subviews[fromIndex]; - subviews.splice(fromIndex, 1); - subviews.splice(toIndex, 0, itemView); - } - }); - } - }); - - if (eachView.elseFunc && eachView.numItems === 0) { - eachView.inElseMode = true; - eachView.initialSubviews[0] = - Blaze.View('each_else', eachView.elseFunc); - } - }); - - eachView.onViewDestroyed(function () { - if (eachView.stopHandle) - eachView.stopHandle.stop(); - }); - - return eachView; -}; - -Blaze._TemplateWith = function (arg, contentFunc) { - var w; - - var argFunc = arg; - if (typeof arg !== 'function') { - argFunc = function () { - return arg; - }; - } - - // This is a little messy. When we compile `{{> Template.contentBlock}}`, we - // wrap it in Blaze._InOuterTemplateScope in order to skip the intermediate - // parent Views in the current template. However, when there's an argument - // (`{{> Template.contentBlock arg}}`), the argument needs to be evaluated - // in the original scope. There's no good order to nest - // Blaze._InOuterTemplateScope and Spacebars.TemplateWith to achieve this, - // so we wrap argFunc to run it in the "original parentView" of the - // Blaze._InOuterTemplateScope. - // - // To make this better, reconsider _InOuterTemplateScope as a primitive. - // Longer term, evaluate expressions in the proper lexical scope. - var wrappedArgFunc = function () { - var viewToEvaluateArg = null; - if (w.parentView && w.parentView.name === 'InOuterTemplateScope') { - viewToEvaluateArg = w.parentView.originalParentView; - } - if (viewToEvaluateArg) { - return Blaze._withCurrentView(viewToEvaluateArg, argFunc); - } else { - return argFunc(); - } - }; - - var wrappedContentFunc = function () { - var content = contentFunc.call(this); - - // Since we are generating the Blaze._TemplateWith view for the - // user, set the flag on the child view. If `content` is a template, - // construct the View so that we can set the flag. - if (content instanceof Blaze.Template) { - content = content.constructView(); - } - if (content instanceof Blaze.View) { - content._hasGeneratedParent = true; - } - - return content; - }; - - w = Blaze.With(wrappedArgFunc, wrappedContentFunc); - w.__isTemplateWith = true; - return w; -}; - -Blaze._InOuterTemplateScope = function (templateView, contentFunc) { - var view = Blaze.View('InOuterTemplateScope', contentFunc); - var parentView = templateView.parentView; - - // Hack so that if you call `{{> foo bar}}` and it expands into - // `{{#with bar}}{{> foo}}{{/with}}`, and then `foo` is a template - // that inserts `{{> Template.contentBlock}}`, the data context for - // `Template.contentBlock` is not `bar` but the one enclosing that. - if (parentView.__isTemplateWith) - parentView = parentView.parentView; - - view.onViewCreated(function () { - this.originalParentView = this.parentView; - this.parentView = parentView; - this.__childDoesntStartNewLexicalScope = true; - }); - return view; -}; - -// XXX COMPAT WITH 0.9.0 -Blaze.InOuterTemplateScope = Blaze._InOuterTemplateScope; diff --git a/packages/blaze/dombackend.js b/packages/blaze/dombackend.js deleted file mode 100644 index 361e37ae5e..0000000000 --- a/packages/blaze/dombackend.js +++ /dev/null @@ -1,179 +0,0 @@ -var DOMBackend = {}; -Blaze._DOMBackend = DOMBackend; - -var $jq = (typeof jQuery !== 'undefined' ? jQuery : - (typeof Package !== 'undefined' ? - Package.jquery && Package.jquery.jQuery : null)); -if (! $jq) - throw new Error("jQuery not found"); - -DOMBackend._$jq = $jq; - -DOMBackend.parseHTML = function (html) { - // Return an array of nodes. - // - // jQuery does fancy stuff like creating an appropriate - // container element and setting innerHTML on it, as well - // as working around various IE quirks. - return $jq.parseHTML(html) || []; -}; - -DOMBackend.Events = { - // `selector` is non-null. `type` is one type (but - // may be in backend-specific form, e.g. have namespaces). - // Order fired must be order bound. - delegateEvents: function (elem, type, selector, handler) { - $jq(elem).on(type, selector, handler); - }, - - undelegateEvents: function (elem, type, handler) { - $jq(elem).off(type, '**', handler); - }, - - bindEventCapturer: function (elem, type, selector, handler) { - var $elem = $jq(elem); - - var wrapper = function (event) { - event = $jq.event.fix(event); - event.currentTarget = event.target; - - // Note: It might improve jQuery interop if we called into jQuery - // here somehow. Since we don't use jQuery to dispatch the event, - // we don't fire any of jQuery's event hooks or anything. However, - // since jQuery can't bind capturing handlers, it's not clear - // where we would hook in. Internal jQuery functions like `dispatch` - // are too high-level. - var $target = $jq(event.currentTarget); - if ($target.is($elem.find(selector))) - handler.call(elem, event); - }; - - handler._meteorui_wrapper = wrapper; - - type = DOMBackend.Events.parseEventType(type); - // add *capturing* event listener - elem.addEventListener(type, wrapper, true); - }, - - unbindEventCapturer: function (elem, type, handler) { - type = DOMBackend.Events.parseEventType(type); - elem.removeEventListener(type, handler._meteorui_wrapper, true); - }, - - parseEventType: function (type) { - // strip off namespaces - var dotLoc = type.indexOf('.'); - if (dotLoc >= 0) - return type.slice(0, dotLoc); - return type; - } -}; - - -///// Removal detection and interoperability. - -// For an explanation of this technique, see: -// http://bugs.jquery.com/ticket/12213#comment:23 . -// -// In short, an element is considered "removed" when jQuery -// cleans up its *private* userdata on the element, -// which we can detect using a custom event with a teardown -// hook. - -var NOOP = function () {}; - -// Circular doubly-linked list -var TeardownCallback = function (func) { - this.next = this; - this.prev = this; - this.func = func; -}; - -// Insert newElt before oldElt in the circular list -TeardownCallback.prototype.linkBefore = function(oldElt) { - this.prev = oldElt.prev; - this.next = oldElt; - oldElt.prev.next = this; - oldElt.prev = this; -}; - -TeardownCallback.prototype.unlink = function () { - this.prev.next = this.next; - this.next.prev = this.prev; -}; - -TeardownCallback.prototype.go = function () { - var func = this.func; - func && func(); -}; - -TeardownCallback.prototype.stop = TeardownCallback.prototype.unlink; - -DOMBackend.Teardown = { - _JQUERY_EVENT_NAME: 'blaze_teardown_watcher', - _CB_PROP: '$blaze_teardown_callbacks', - // Registers a callback function to be called when the given element or - // one of its ancestors is removed from the DOM via the backend library. - // The callback function is called at most once, and it receives the element - // in question as an argument. - onElementTeardown: function (elem, func) { - var elt = new TeardownCallback(func); - - var propName = DOMBackend.Teardown._CB_PROP; - if (! elem[propName]) { - // create an empty node that is never unlinked - elem[propName] = new TeardownCallback; - - // Set up the event, only the first time. - $jq(elem).on(DOMBackend.Teardown._JQUERY_EVENT_NAME, NOOP); - } - - elt.linkBefore(elem[propName]); - - return elt; // so caller can call stop() - }, - // Recursively call all teardown hooks, in the backend and registered - // through DOMBackend.onElementTeardown. - tearDownElement: function (elem) { - var elems = []; - // Array.prototype.slice.call doesn't work when given a NodeList in - // IE8 ("JScript object expected"). - var nodeList = elem.getElementsByTagName('*'); - for (var i = 0; i < nodeList.length; i++) { - elems.push(nodeList[i]); - } - elems.push(elem); - $jq.cleanData(elems); - } -}; - -$jq.event.special[DOMBackend.Teardown._JQUERY_EVENT_NAME] = { - setup: function () { - // This "setup" callback is important even though it is empty! - // Without it, jQuery will call addEventListener, which is a - // performance hit, especially with Chrome's async stack trace - // feature enabled. - }, - teardown: function() { - var elem = this; - var callbacks = elem[DOMBackend.Teardown._CB_PROP]; - if (callbacks) { - var elt = callbacks.next; - while (elt !== callbacks) { - elt.go(); - elt = elt.next; - } - callbacks.go(); - - elem[DOMBackend.Teardown._CB_PROP] = null; - } - } -}; - - -// Must use jQuery semantics for `context`, not -// querySelectorAll's. In other words, all the parts -// of `selector` must be found under `context`. -DOMBackend.findBySelector = function (selector, context) { - return $jq(selector, context); -}; diff --git a/packages/blaze/domrange.js b/packages/blaze/domrange.js deleted file mode 100644 index ca39ac459c..0000000000 --- a/packages/blaze/domrange.js +++ /dev/null @@ -1,485 +0,0 @@ - -// A constant empty array (frozen if the JS engine supports it). -var _emptyArray = Object.freeze ? Object.freeze([]) : []; - -// `[new] Blaze._DOMRange([nodeAndRangeArray])` -// -// A DOMRange consists of an array of consecutive nodes and DOMRanges, -// which may be replaced at any time with a new array. If the DOMRange -// has been attached to the DOM at some location, then updating -// the array will cause the DOM to be updated at that location. -Blaze._DOMRange = function (nodeAndRangeArray) { - if (! (this instanceof DOMRange)) - // called without `new` - return new DOMRange(nodeAndRangeArray); - - var members = (nodeAndRangeArray || _emptyArray); - if (! (members && (typeof members.length) === 'number')) - throw new Error("Expected array"); - - for (var i = 0; i < members.length; i++) - this._memberIn(members[i]); - - this.members = members; - this.emptyRangePlaceholder = null; - this.attached = false; - this.parentElement = null; - this.parentRange = null; - this.attachedCallbacks = _emptyArray; -}; -var DOMRange = Blaze._DOMRange; - -// In IE 8, don't use empty text nodes as placeholders -// in empty DOMRanges, use comment nodes instead. Using -// empty text nodes in modern browsers is great because -// it doesn't clutter the web inspector. In IE 8, however, -// it seems to lead in some roundabout way to the OAuth -// pop-up crashing the browser completely. In the past, -// we didn't use empty text nodes on IE 8 because they -// don't accept JS properties, so just use the same logic -// even though we don't need to set properties on the -// placeholder anymore. -DOMRange._USE_COMMENT_PLACEHOLDERS = (function () { - var result = false; - var textNode = document.createTextNode(""); - try { - textNode.someProp = true; - } catch (e) { - // IE 8 - result = true; - } - return result; -})(); - -// static methods -DOMRange._insert = function (rangeOrNode, parentElement, nextNode, _isMove) { - var m = rangeOrNode; - if (m instanceof DOMRange) { - m.attach(parentElement, nextNode, _isMove); - } else { - if (_isMove) - DOMRange._moveNodeWithHooks(m, parentElement, nextNode); - else - DOMRange._insertNodeWithHooks(m, parentElement, nextNode); - } -}; - -DOMRange._remove = function (rangeOrNode) { - var m = rangeOrNode; - if (m instanceof DOMRange) { - m.detach(); - } else { - DOMRange._removeNodeWithHooks(m); - } -}; - -DOMRange._removeNodeWithHooks = function (n) { - if (! n.parentNode) - return; - if (n.nodeType === 1 && - n.parentNode._uihooks && n.parentNode._uihooks.removeElement) { - n.parentNode._uihooks.removeElement(n); - } else { - n.parentNode.removeChild(n); - } -}; - -DOMRange._insertNodeWithHooks = function (n, parent, next) { - // `|| null` because IE throws an error if 'next' is undefined - next = next || null; - if (n.nodeType === 1 && - parent._uihooks && parent._uihooks.insertElement) { - parent._uihooks.insertElement(n, next); - } else { - parent.insertBefore(n, next); - } -}; - -DOMRange._moveNodeWithHooks = function (n, parent, next) { - if (n.parentNode !== parent) - return; - // `|| null` because IE throws an error if 'next' is undefined - next = next || null; - if (n.nodeType === 1 && - parent._uihooks && parent._uihooks.moveElement) { - parent._uihooks.moveElement(n, next); - } else { - parent.insertBefore(n, next); - } -}; - -DOMRange.forElement = function (elem) { - if (elem.nodeType !== 1) - throw new Error("Expected element, found: " + elem); - var range = null; - while (elem && ! range) { - range = (elem.$blaze_range || null); - if (! range) - elem = elem.parentNode; - } - return range; -}; - -DOMRange.prototype.attach = function (parentElement, nextNode, _isMove, _isReplace) { - // This method is called to insert the DOMRange into the DOM for - // the first time, but it's also used internally when - // updating the DOM. - // - // If _isMove is true, move this attached range to a different - // location under the same parentElement. - if (_isMove || _isReplace) { - if (! (this.parentElement === parentElement && - this.attached)) - throw new Error("Can only move or replace an attached DOMRange, and only under the same parent element"); - } - - var members = this.members; - if (members.length) { - this.emptyRangePlaceholder = null; - for (var i = 0; i < members.length; i++) { - DOMRange._insert(members[i], parentElement, nextNode, _isMove); - } - } else { - var placeholder = ( - DOMRange._USE_COMMENT_PLACEHOLDERS ? - document.createComment("") : - document.createTextNode("")); - this.emptyRangePlaceholder = placeholder; - parentElement.insertBefore(placeholder, nextNode || null); - } - this.attached = true; - this.parentElement = parentElement; - - if (! (_isMove || _isReplace)) { - for(var i = 0; i < this.attachedCallbacks.length; i++) { - var obj = this.attachedCallbacks[i]; - obj.attached && obj.attached(this, parentElement); - } - } -}; - -DOMRange.prototype.setMembers = function (newNodeAndRangeArray) { - var newMembers = newNodeAndRangeArray; - if (! (newMembers && (typeof newMembers.length) === 'number')) - throw new Error("Expected array"); - - var oldMembers = this.members; - - for (var i = 0; i < oldMembers.length; i++) - this._memberOut(oldMembers[i]); - for (var i = 0; i < newMembers.length; i++) - this._memberIn(newMembers[i]); - - if (! this.attached) { - this.members = newMembers; - } else { - // don't do anything if we're going from empty to empty - if (newMembers.length || oldMembers.length) { - // detach the old members and insert the new members - var nextNode = this.lastNode().nextSibling; - var parentElement = this.parentElement; - // Use detach/attach, but don't fire attached/detached hooks - this.detach(true /*_isReplace*/); - this.members = newMembers; - this.attach(parentElement, nextNode, false, true /*_isReplace*/); - } - } -}; - -DOMRange.prototype.firstNode = function () { - if (! this.attached) - throw new Error("Must be attached"); - - if (! this.members.length) - return this.emptyRangePlaceholder; - - var m = this.members[0]; - return (m instanceof DOMRange) ? m.firstNode() : m; -}; - -DOMRange.prototype.lastNode = function () { - if (! this.attached) - throw new Error("Must be attached"); - - if (! this.members.length) - return this.emptyRangePlaceholder; - - var m = this.members[this.members.length - 1]; - return (m instanceof DOMRange) ? m.lastNode() : m; -}; - -DOMRange.prototype.detach = function (_isReplace) { - if (! this.attached) - throw new Error("Must be attached"); - - var oldParentElement = this.parentElement; - var members = this.members; - if (members.length) { - for (var i = 0; i < members.length; i++) { - DOMRange._remove(members[i]); - } - } else { - var placeholder = this.emptyRangePlaceholder; - this.parentElement.removeChild(placeholder); - this.emptyRangePlaceholder = null; - } - - if (! _isReplace) { - this.attached = false; - this.parentElement = null; - - for(var i = 0; i < this.attachedCallbacks.length; i++) { - var obj = this.attachedCallbacks[i]; - obj.detached && obj.detached(this, oldParentElement); - } - } -}; - -DOMRange.prototype.addMember = function (newMember, atIndex, _isMove) { - var members = this.members; - if (! (atIndex >= 0 && atIndex <= members.length)) - throw new Error("Bad index in range.addMember: " + atIndex); - - if (! _isMove) - this._memberIn(newMember); - - if (! this.attached) { - // currently detached; just updated members - members.splice(atIndex, 0, newMember); - } else if (members.length === 0) { - // empty; use the empty-to-nonempty handling of setMembers - this.setMembers([newMember]); - } else { - var nextNode; - if (atIndex === members.length) { - // insert at end - nextNode = this.lastNode().nextSibling; - } else { - var m = members[atIndex]; - nextNode = (m instanceof DOMRange) ? m.firstNode() : m; - } - members.splice(atIndex, 0, newMember); - DOMRange._insert(newMember, this.parentElement, nextNode, _isMove); - } -}; - -DOMRange.prototype.removeMember = function (atIndex, _isMove) { - var members = this.members; - if (! (atIndex >= 0 && atIndex < members.length)) - throw new Error("Bad index in range.removeMember: " + atIndex); - - if (_isMove) { - members.splice(atIndex, 1); - } else { - var oldMember = members[atIndex]; - this._memberOut(oldMember); - - if (members.length === 1) { - // becoming empty; use the logic in setMembers - this.setMembers(_emptyArray); - } else { - members.splice(atIndex, 1); - if (this.attached) - DOMRange._remove(oldMember); - } - } -}; - -DOMRange.prototype.moveMember = function (oldIndex, newIndex) { - var member = this.members[oldIndex]; - this.removeMember(oldIndex, true /*_isMove*/); - this.addMember(member, newIndex, true /*_isMove*/); -}; - -DOMRange.prototype.getMember = function (atIndex) { - var members = this.members; - if (! (atIndex >= 0 && atIndex < members.length)) - throw new Error("Bad index in range.getMember: " + atIndex); - return this.members[atIndex]; -}; - -DOMRange.prototype._memberIn = function (m) { - if (m instanceof DOMRange) - m.parentRange = this; - else if (m.nodeType === 1) // DOM Element - m.$blaze_range = this; -}; - -DOMRange._destroy = function (m, _skipNodes) { - if (m instanceof DOMRange) { - if (m.view) - Blaze._destroyView(m.view, _skipNodes); - } else if ((! _skipNodes) && m.nodeType === 1) { - // DOM Element - if (m.$blaze_range) { - Blaze._destroyNode(m); - m.$blaze_range = null; - } - } -}; - -DOMRange.prototype._memberOut = DOMRange._destroy; - -// Tear down, but don't remove, the members. Used when chunks -// of DOM are being torn down or replaced. -DOMRange.prototype.destroyMembers = function (_skipNodes) { - var members = this.members; - for (var i = 0; i < members.length; i++) - this._memberOut(members[i], _skipNodes); -}; - -DOMRange.prototype.destroy = function (_skipNodes) { - DOMRange._destroy(this, _skipNodes); -}; - -DOMRange.prototype.containsElement = function (elem) { - if (! this.attached) - throw new Error("Must be attached"); - - // An element is contained in this DOMRange if it's possible to - // reach it by walking parent pointers, first through the DOM and - // then parentRange pointers. In other words, the element or some - // ancestor of it is at our level of the DOM (a child of our - // parentElement), and this element is one of our members or - // is a member of a descendant Range. - - // First check that elem is a descendant of this.parentElement, - // according to the DOM. - if (! Blaze._elementContains(this.parentElement, elem)) - return false; - - // If elem is not an immediate child of this.parentElement, - // walk up to its ancestor that is. - while (elem.parentNode !== this.parentElement) - elem = elem.parentNode; - - var range = elem.$blaze_range; - while (range && range !== this) - range = range.parentRange; - - return range === this; -}; - -DOMRange.prototype.containsRange = function (range) { - if (! this.attached) - throw new Error("Must be attached"); - - if (! range.attached) - return false; - - // A DOMRange is contained in this DOMRange if it's possible - // to reach this range by following parent pointers. If the - // DOMRange has the same parentElement, then it should be - // a member, or a member of a member etc. Otherwise, we must - // contain its parentElement. - - if (range.parentElement !== this.parentElement) - return this.containsElement(range.parentElement); - - if (range === this) - return false; // don't contain self - - while (range && range !== this) - range = range.parentRange; - - return range === this; -}; - -DOMRange.prototype.onAttached = function (attached) { - this.onAttachedDetached({ attached: attached }); -}; - -// callbacks are `attached(range, element)` and -// `detached(range, element)`, and they may -// access the `callbacks` object in `this`. -// The arguments to `detached` are the same -// range and element that were passed to `attached`. -DOMRange.prototype.onAttachedDetached = function (callbacks) { - if (this.attachedCallbacks === _emptyArray) - this.attachedCallbacks = []; - this.attachedCallbacks.push(callbacks); -}; - -DOMRange.prototype.$ = function (selector) { - var self = this; - - var parentNode = this.parentElement; - if (! parentNode) - throw new Error("Can't select in removed DomRange"); - - // Strategy: Find all selector matches under parentNode, - // then filter out the ones that aren't in this DomRange - // using `DOMRange#containsElement`. This is - // asymptotically slow in the presence of O(N) sibling - // content that is under parentNode but not in our range, - // so if performance is an issue, the selector should be - // run on a child element. - - // Since jQuery can't run selectors on a DocumentFragment, - // we don't expect findBySelector to work. - if (parentNode.nodeType === 11 /* DocumentFragment */) - throw new Error("Can't use $ on an offscreen range"); - - var results = Blaze._DOMBackend.findBySelector(selector, parentNode); - - // We don't assume `results` has jQuery API; a plain array - // should do just as well. However, if we do have a jQuery - // array, we want to end up with one also, so we use - // `.filter`. - - // Function that selects only elements that are actually - // in this DomRange, rather than simply descending from - // `parentNode`. - var filterFunc = function (elem) { - // handle jQuery's arguments to filter, where the node - // is in `this` and the index is the first argument. - if (typeof elem === 'number') - elem = this; - - return self.containsElement(elem); - }; - - if (! results.filter) { - // not a jQuery array, and not a browser with - // Array.prototype.filter (e.g. IE <9) - var newResults = []; - for (var i = 0; i < results.length; i++) { - var x = results[i]; - if (filterFunc(x)) - newResults.push(x); - } - results = newResults; - } else { - // `results.filter` is either jQuery's or ECMAScript's `filter` - results = results.filter(filterFunc); - } - - return results; -}; - -// Returns true if element a contains node b and is not node b. -// -// The restriction that `a` be an element (not a document fragment, -// say) is based on what's easy to implement cross-browser. -Blaze._elementContains = function (a, b) { - if (a.nodeType !== 1) // ELEMENT - return false; - if (a === b) - return false; - - if (a.compareDocumentPosition) { - return a.compareDocumentPosition(b) & 0x10; - } else { - // Should be only old IE and maybe other old browsers here. - // Modern Safari has both functions but seems to get contains() wrong. - // IE can't handle b being a text node. We work around this - // by doing a direct parent test now. - b = b.parentNode; - if (! (b && b.nodeType === 1)) // ELEMENT - return false; - if (a === b) - return true; - - return a.contains(b); - } -}; diff --git a/packages/blaze/events.js b/packages/blaze/events.js deleted file mode 100644 index 7b9faf10a1..0000000000 --- a/packages/blaze/events.js +++ /dev/null @@ -1,204 +0,0 @@ -var EventSupport = Blaze._EventSupport = {}; - -var DOMBackend = Blaze._DOMBackend; - -// List of events to always delegate, never capture. -// Since jQuery fakes bubbling for certain events in -// certain browsers (like `submit`), we don't want to -// get in its way. -// -// We could list all known bubbling -// events here to avoid creating speculative capturers -// for them, but it would only be an optimization. -var eventsToDelegate = EventSupport.eventsToDelegate = { - blur: 1, change: 1, click: 1, focus: 1, focusin: 1, - focusout: 1, reset: 1, submit: 1 -}; - -var EVENT_MODE = EventSupport.EVENT_MODE = { - TBD: 0, - BUBBLING: 1, - CAPTURING: 2 -}; - -var NEXT_HANDLERREC_ID = 1; - -var HandlerRec = function (elem, type, selector, handler, recipient) { - this.elem = elem; - this.type = type; - this.selector = selector; - this.handler = handler; - this.recipient = recipient; - this.id = (NEXT_HANDLERREC_ID++); - - this.mode = EVENT_MODE.TBD; - - // It's important that delegatedHandler be a different - // instance for each handlerRecord, because its identity - // is used to remove it. - // - // It's also important that the closure have access to - // `this` when it is not called with it set. - this.delegatedHandler = (function (h) { - return function (evt) { - if ((! h.selector) && evt.currentTarget !== evt.target) - // no selector means only fire on target - return; - return h.handler.apply(h.recipient, arguments); - }; - })(this); - - // WHY CAPTURE AND DELEGATE: jQuery can't delegate - // non-bubbling events, because - // event capture doesn't work in IE 8. However, there - // are all sorts of new-fangled non-bubbling events - // like "play" and "touchenter". We delegate these - // events using capture in all browsers except IE 8. - // IE 8 doesn't support these events anyway. - - var tryCapturing = elem.addEventListener && - (! _.has(eventsToDelegate, - DOMBackend.Events.parseEventType(type))); - - if (tryCapturing) { - this.capturingHandler = (function (h) { - return function (evt) { - if (h.mode === EVENT_MODE.TBD) { - // must be first time we're called. - if (evt.bubbles) { - // this type of event bubbles, so don't - // get called again. - h.mode = EVENT_MODE.BUBBLING; - DOMBackend.Events.unbindEventCapturer( - h.elem, h.type, h.capturingHandler); - return; - } else { - // this type of event doesn't bubble, - // so unbind the delegation, preventing - // it from ever firing. - h.mode = EVENT_MODE.CAPTURING; - DOMBackend.Events.undelegateEvents( - h.elem, h.type, h.delegatedHandler); - } - } - - h.delegatedHandler(evt); - }; - })(this); - - } else { - this.mode = EVENT_MODE.BUBBLING; - } -}; -EventSupport.HandlerRec = HandlerRec; - -HandlerRec.prototype.bind = function () { - // `this.mode` may be EVENT_MODE_TBD, in which case we bind both. in - // this case, 'capturingHandler' is in charge of detecting the - // correct mode and turning off one or the other handlers. - if (this.mode !== EVENT_MODE.BUBBLING) { - DOMBackend.Events.bindEventCapturer( - this.elem, this.type, this.selector || '*', - this.capturingHandler); - } - - if (this.mode !== EVENT_MODE.CAPTURING) - DOMBackend.Events.delegateEvents( - this.elem, this.type, - this.selector || '*', this.delegatedHandler); -}; - -HandlerRec.prototype.unbind = function () { - if (this.mode !== EVENT_MODE.BUBBLING) - DOMBackend.Events.unbindEventCapturer(this.elem, this.type, - this.capturingHandler); - - if (this.mode !== EVENT_MODE.CAPTURING) - DOMBackend.Events.undelegateEvents(this.elem, this.type, - this.delegatedHandler); -}; - -EventSupport.listen = function (element, events, selector, handler, recipient, getParentRecipient) { - - // Prevent this method from being JITed by Safari. Due to a - // presumed JIT bug in Safari -- observed in Version 7.0.6 - // (9537.78.2) -- this method may crash the Safari render process if - // it is JITed. - // Repro: https://github.com/dgreensp/public/tree/master/safari-crash - try { element = element; } finally {} - - var eventTypes = []; - events.replace(/[^ /]+/g, function (e) { - eventTypes.push(e); - }); - - var newHandlerRecs = []; - for (var i = 0, N = eventTypes.length; i < N; i++) { - var type = eventTypes[i]; - - var eventDict = element.$blaze_events; - if (! eventDict) - eventDict = (element.$blaze_events = {}); - - var info = eventDict[type]; - if (! info) { - info = eventDict[type] = {}; - info.handlers = []; - } - var handlerList = info.handlers; - var handlerRec = new HandlerRec( - element, type, selector, handler, recipient); - newHandlerRecs.push(handlerRec); - handlerRec.bind(); - handlerList.push(handlerRec); - // Move handlers of enclosing ranges to end, by unbinding and rebinding - // them. In jQuery (or other DOMBackend) this causes them to fire - // later when the backend dispatches event handlers. - if (getParentRecipient) { - for (var r = getParentRecipient(recipient); r; - r = getParentRecipient(r)) { - // r is an enclosing range (recipient) - for (var j = 0, Nj = handlerList.length; - j < Nj; j++) { - var h = handlerList[j]; - if (h.recipient === r) { - h.unbind(); - h.bind(); - handlerList.splice(j, 1); // remove handlerList[j] - handlerList.push(h); - j--; // account for removed handler - Nj--; // don't visit appended handlers - } - } - } - } - } - - return { - // closes over just `element` and `newHandlerRecs` - stop: function () { - var eventDict = element.$blaze_events; - if (! eventDict) - return; - // newHandlerRecs has only one item unless you specify multiple - // event types. If this code is slow, it's because we have to - // iterate over handlerList here. Clearing a whole handlerList - // via stop() methods is O(N^2) in the number of handlers on - // an element. - for (var i = 0; i < newHandlerRecs.length; i++) { - var handlerToRemove = newHandlerRecs[i]; - var info = eventDict[handlerToRemove.type]; - if (! info) - continue; - var handlerList = info.handlers; - for (var j = handlerList.length - 1; j >= 0; j--) { - if (handlerList[j] === handlerToRemove) { - handlerToRemove.unbind(); - handlerList.splice(j, 1); // remove handlerList[j] - } - } - } - newHandlerRecs.length = 0; - } - }; -}; diff --git a/packages/blaze/exceptions.js b/packages/blaze/exceptions.js deleted file mode 100644 index 429ac82f73..0000000000 --- a/packages/blaze/exceptions.js +++ /dev/null @@ -1,56 +0,0 @@ -var debugFunc; - -// We call into user code in many places, and it's nice to catch exceptions -// propagated from user code immediately so that the whole system doesn't just -// break. Catching exceptions is easy; reporting them is hard. This helper -// reports exceptions. -// -// Usage: -// -// ``` -// try { -// // ... someStuff ... -// } catch (e) { -// reportUIException(e); -// } -// ``` -// -// An optional second argument overrides the default message. - -// Set this to `true` to cause `reportException` to throw -// the next exception rather than reporting it. This is -// useful in unit tests that test error messages. -Blaze._throwNextException = false; - -Blaze._reportException = function (e, msg) { - if (Blaze._throwNextException) { - Blaze._throwNextException = false; - throw e; - } - - if (! debugFunc) - // adapted from Tracker - debugFunc = function () { - return (typeof Meteor !== "undefined" ? Meteor._debug : - ((typeof console !== "undefined") && console.log ? console.log : - function () {})); - }; - - // In Chrome, `e.stack` is a multiline string that starts with the message - // and contains a stack trace. Furthermore, `console.log` makes it clickable. - // `console.log` supplies the space between the two arguments. - debugFunc()(msg || 'Exception caught in template:', e.stack || e.message || e); -}; - -Blaze._wrapCatchingExceptions = function (f, where) { - if (typeof f !== 'function') - return f; - - return function () { - try { - return f.apply(this, arguments); - } catch (e) { - Blaze._reportException(e, 'Exception in ' + where + ':'); - } - }; -}; diff --git a/packages/blaze/lookup.js b/packages/blaze/lookup.js deleted file mode 100644 index 932b82054d..0000000000 --- a/packages/blaze/lookup.js +++ /dev/null @@ -1,238 +0,0 @@ -Blaze._globalHelpers = {}; - -// Documented as Template.registerHelper. -// This definition also provides back-compat for `UI.registerHelper`. -Blaze.registerHelper = function (name, func) { - Blaze._globalHelpers[name] = func; -}; - -// Also documented as Template.deregisterHelper -Blaze.deregisterHelper = function(name) { - delete Blaze._globalHelpers[name]; -} - -var bindIfIsFunction = function (x, target) { - if (typeof x !== 'function') - return x; - return _.bind(x, target); -}; - -// If `x` is a function, binds the value of `this` for that function -// to the current data context. -var bindDataContext = function (x) { - if (typeof x === 'function') { - return function () { - var data = Blaze.getData(); - if (data == null) - data = {}; - return x.apply(data, arguments); - }; - } - return x; -}; - -Blaze._OLDSTYLE_HELPER = {}; - -Blaze._getTemplateHelper = function (template, name, tmplInstanceFunc) { - // XXX COMPAT WITH 0.9.3 - var isKnownOldStyleHelper = false; - - if (template.__helpers.has(name)) { - var helper = template.__helpers.get(name); - if (helper === Blaze._OLDSTYLE_HELPER) { - isKnownOldStyleHelper = true; - } else if (helper != null) { - return wrapHelper(bindDataContext(helper), tmplInstanceFunc); - } else { - return null; - } - } - - // old-style helper - if (name in template) { - // Only warn once per helper - if (! isKnownOldStyleHelper) { - template.__helpers.set(name, Blaze._OLDSTYLE_HELPER); - if (! template._NOWARN_OLDSTYLE_HELPERS) { - Blaze._warn('Assigning helper with `' + template.viewName + '.' + - name + ' = ...` is deprecated. Use `' + template.viewName + - '.helpers(...)` instead.'); - } - } - if (template[name] != null) { - return wrapHelper(bindDataContext(template[name]), tmplInstanceFunc); - } - } - - return null; -}; - -var wrapHelper = function (f, templateFunc) { - if (typeof f !== "function") { - return f; - } - - return function () { - var self = this; - var args = arguments; - - return Blaze.Template._withTemplateInstanceFunc(templateFunc, function () { - return Blaze._wrapCatchingExceptions(f, 'template helper').apply(self, args); - }); - }; -}; - -Blaze._lexicalBindingLookup = function (view, name) { - var currentView = view; - var blockHelpersStack = []; - - // walk up the views stopping at a Spacebars.include or Template view that - // doesn't have an InOuterTemplateScope view as a parent - do { - // skip block helpers views - // if we found the binding on the scope, return it - if (_.has(currentView._scopeBindings, name)) { - var bindingReactiveVar = currentView._scopeBindings[name]; - return function () { - return bindingReactiveVar.get(); - }; - } - } while (! (currentView.__startsNewLexicalScope && - ! (currentView.parentView && - currentView.parentView.__childDoesntStartNewLexicalScope)) - && (currentView = currentView.parentView)); - - return null; -}; - -// templateInstance argument is provided to be available for possible -// alternative implementations of this function by 3rd party packages. -Blaze._getTemplate = function (name, templateInstance) { - if ((name in Blaze.Template) && (Blaze.Template[name] instanceof Blaze.Template)) { - return Blaze.Template[name]; - } - return null; -}; - -Blaze._getGlobalHelper = function (name, templateInstance) { - if (Blaze._globalHelpers[name] != null) { - return wrapHelper(bindDataContext(Blaze._globalHelpers[name]), templateInstance); - } - return null; -}; - -// Looks up a name, like "foo" or "..", as a helper of the -// current template; the name of a template; a global helper; -// or a property of the data context. Called on the View of -// a template (i.e. a View with a `.template` property, -// where the helpers are). Used for the first name in a -// "path" in a template tag, like "foo" in `{{foo.bar}}` or -// ".." in `{{frobulate ../blah}}`. -// -// Returns a function, a non-function value, or null. If -// a function is found, it is bound appropriately. -// -// NOTE: This function must not establish any reactive -// dependencies itself. If there is any reactivity in the -// value, lookup should return a function. -Blaze.View.prototype.lookup = function (name, _options) { - var template = this.template; - var lookupTemplate = _options && _options.template; - var helper; - var binding; - var boundTmplInstance; - var foundTemplate; - - if (this.templateInstance) { - boundTmplInstance = _.bind(this.templateInstance, this); - } - - // 0. looking up the parent data context with the special "../" syntax - if (/^\./.test(name)) { - // starts with a dot. must be a series of dots which maps to an - // ancestor of the appropriate height. - if (!/^(\.)+$/.test(name)) - throw new Error("id starting with dot must be a series of dots"); - - return Blaze._parentData(name.length - 1, true /*_functionWrapped*/); - - } - - // 1. look up a helper on the current template - if (template && ((helper = Blaze._getTemplateHelper(template, name, boundTmplInstance)) != null)) { - return helper; - } - - // 2. look up a binding by traversing the lexical view hierarchy inside the - // current template - if (template && (binding = Blaze._lexicalBindingLookup(Blaze.currentView, name)) != null) { - return binding; - } - - // 3. look up a template by name - if (lookupTemplate && ((foundTemplate = Blaze._getTemplate(name, boundTmplInstance)) != null)) { - return foundTemplate; - } - - // 4. look up a global helper - if ((helper = Blaze._getGlobalHelper(name, boundTmplInstance)) != null) { - return helper; - } - - // 5. look up in a data context - return function () { - var isCalledAsFunction = (arguments.length > 0); - var data = Blaze.getData(); - var x = data && data[name]; - if (! x) { - if (lookupTemplate) { - throw new Error("No such template: " + name); - } else if (isCalledAsFunction) { - throw new Error("No such function: " + name); - } else if (name.charAt(0) === '@' && ((x === null) || - (x === undefined))) { - // Throw an error if the user tries to use a `@directive` - // that doesn't exist. We don't implement all directives - // from Handlebars, so there's a potential for confusion - // if we fail silently. On the other hand, we want to - // throw late in case some app or package wants to provide - // a missing directive. - throw new Error("Unsupported directive: " + name); - } - } - if (! data) { - return null; - } - if (typeof x !== 'function') { - if (isCalledAsFunction) { - throw new Error("Can't call non-function: " + x); - } - return x; - } - return x.apply(data, arguments); - }; -}; - -// Implement Spacebars' {{../..}}. -// @param height {Number} The number of '..'s -Blaze._parentData = function (height, _functionWrapped) { - // If height is null or undefined, we default to 1, the first parent. - if (height == null) { - height = 1; - } - var theWith = Blaze.getView('with'); - for (var i = 0; (i < height) && theWith; i++) { - theWith = Blaze.getView(theWith, 'with'); - } - - if (! theWith) - return null; - if (_functionWrapped) - return function () { return theWith.dataVar.get(); }; - return theWith.dataVar.get(); -}; - - -Blaze.View.prototype.lookupTemplate = function (name) { - return this.lookup(name, {template:true}); -}; diff --git a/packages/blaze/materializer.js b/packages/blaze/materializer.js deleted file mode 100644 index 4986750e05..0000000000 --- a/packages/blaze/materializer.js +++ /dev/null @@ -1,191 +0,0 @@ -// Turns HTMLjs into DOM nodes and DOMRanges. -// -// - `htmljs`: the value to materialize, which may be any of the htmljs -// types (Tag, CharRef, Comment, Raw, array, string, boolean, number, -// null, or undefined) or a View or Template (which will be used to -// construct a View). -// - `intoArray`: the array of DOM nodes and DOMRanges to push the output -// into (required) -// - `parentView`: the View we are materializing content for (optional) -// - `_existingWorkStack`: optional argument, only used for recursive -// calls when there is some other _materializeDOM on the call stack. -// If _materializeDOM called your function and passed in a workStack, -// pass it back when you call _materializeDOM (such as from a workStack -// task). -// -// Returns `intoArray`, which is especially useful if you pass in `[]`. -Blaze._materializeDOM = function (htmljs, intoArray, parentView, - _existingWorkStack) { - // In order to use fewer stack frames, materializeDOMInner can push - // tasks onto `workStack`, and they will be popped off - // and run, last first, after materializeDOMInner returns. The - // reason we use a stack instead of a queue is so that we recurse - // depth-first, doing newer tasks first. - var workStack = (_existingWorkStack || []); - materializeDOMInner(htmljs, intoArray, parentView, workStack); - - if (! _existingWorkStack) { - // We created the work stack, so we are responsible for finishing - // the work. Call each "task" function, starting with the top - // of the stack. - while (workStack.length) { - // Note that running task() may push new items onto workStack. - var task = workStack.pop(); - task(); - } - } - - return intoArray; -}; - -var materializeDOMInner = function (htmljs, intoArray, parentView, workStack) { - if (htmljs == null) { - // null or undefined - return; - } - - switch (typeof htmljs) { - case 'string': case 'boolean': case 'number': - intoArray.push(document.createTextNode(String(htmljs))); - return; - case 'object': - if (htmljs.htmljsType) { - switch (htmljs.htmljsType) { - case HTML.Tag.htmljsType: - intoArray.push(materializeTag(htmljs, parentView, workStack)); - return; - case HTML.CharRef.htmljsType: - intoArray.push(document.createTextNode(htmljs.str)); - return; - case HTML.Comment.htmljsType: - intoArray.push(document.createComment(htmljs.sanitizedValue)); - return; - case HTML.Raw.htmljsType: - // Get an array of DOM nodes by using the browser's HTML parser - // (like innerHTML). - var nodes = Blaze._DOMBackend.parseHTML(htmljs.value); - for (var i = 0; i < nodes.length; i++) - intoArray.push(nodes[i]); - return; - } - } else if (HTML.isArray(htmljs)) { - for (var i = htmljs.length-1; i >= 0; i--) { - workStack.push(_.bind(Blaze._materializeDOM, null, - htmljs[i], intoArray, parentView, workStack)); - } - return; - } else { - if (htmljs instanceof Blaze.Template) { - htmljs = htmljs.constructView(); - // fall through to Blaze.View case below - } - if (htmljs instanceof Blaze.View) { - Blaze._materializeView(htmljs, parentView, workStack, intoArray); - return; - } - } - } - - throw new Error("Unexpected object in htmljs: " + htmljs); -}; - -var materializeTag = function (tag, parentView, workStack) { - var tagName = tag.tagName; - var elem; - if ((HTML.isKnownSVGElement(tagName) || isSVGAnchor(tag)) - && document.createElementNS) { - // inline SVG - elem = document.createElementNS('http://www.w3.org/2000/svg', tagName); - } else { - // normal elements - elem = document.createElement(tagName); - } - - var rawAttrs = tag.attrs; - var children = tag.children; - if (tagName === 'textarea' && tag.children.length && - ! (rawAttrs && ('value' in rawAttrs))) { - // Provide very limited support for TEXTAREA tags with children - // rather than a "value" attribute. - // Reactivity in the form of Views nested in the tag's children - // won't work. Compilers should compile textarea contents into - // the "value" attribute of the tag, wrapped in a function if there - // is reactivity. - if (typeof rawAttrs === 'function' || - HTML.isArray(rawAttrs)) { - throw new Error("Can't have reactive children of TEXTAREA node; " + - "use the 'value' attribute instead."); - } - rawAttrs = _.extend({}, rawAttrs || null); - rawAttrs.value = Blaze._expand(children, parentView); - children = []; - } - - if (rawAttrs) { - var attrUpdater = new ElementAttributesUpdater(elem); - var updateAttributes = function () { - var expandedAttrs = Blaze._expandAttributes(rawAttrs, parentView); - var flattenedAttrs = HTML.flattenAttributes(expandedAttrs); - var stringAttrs = {}; - for (var attrName in flattenedAttrs) { - stringAttrs[attrName] = Blaze._toText(flattenedAttrs[attrName], - parentView, - HTML.TEXTMODE.STRING); - } - attrUpdater.update(stringAttrs); - }; - var updaterComputation; - if (parentView) { - updaterComputation = - parentView.autorun(updateAttributes, undefined, 'updater'); - } else { - updaterComputation = Tracker.nonreactive(function () { - return Tracker.autorun(function () { - Tracker._withCurrentView(parentView, updateAttributes); - }); - }); - } - Blaze._DOMBackend.Teardown.onElementTeardown(elem, function attrTeardown() { - updaterComputation.stop(); - }); - } - - if (children.length) { - var childNodesAndRanges = []; - // push this function first so that it's done last - workStack.push(function () { - for (var i = 0; i < childNodesAndRanges.length; i++) { - var x = childNodesAndRanges[i]; - if (x instanceof Blaze._DOMRange) - x.attach(elem); - else - elem.appendChild(x); - } - }); - // now push the task that calculates childNodesAndRanges - workStack.push(_.bind(Blaze._materializeDOM, null, - children, childNodesAndRanges, parentView, - workStack)); - } - - return elem; -}; - - -var isSVGAnchor = function (node) { - // We generally aren't able to detect SVG elements because - // if "A" were in our list of known svg element names, then all - // nodes would be created using - // `document.createElementNS`. But in the special case of , we can at least detect that attribute and - // create an SVG tag in that case. - // - // However, we still have a general problem of knowing when to - // use document.createElementNS and when to use - // document.createElement; for example, font tags will always - // be created as SVG elements which can cause other - // problems. #1977 - return (node.tagName === "a" && - node.attrs && - node.attrs["xlink:href"] !== undefined); -}; diff --git a/packages/blaze/microscore.js b/packages/blaze/microscore.js deleted file mode 100644 index 56e78f6659..0000000000 --- a/packages/blaze/microscore.js +++ /dev/null @@ -1,116 +0,0 @@ -// Microscore is a partial polyfill for Underscore. It implements -// a subset of Underscore functions, and for some functions it -// implements a subset of the full functionality. -// -// Code written against Microscore should just work with Underscore. -// The reverse is not true, because Microscore doesn't support -// all features of every function. A list of known differences -// between Underscore and Microscore is given with each function. -// -// This file should be curated to keep it small, so that it doesn't -// grow into Underscore. -// -// In the future, we'll figure out something better, like package -// slices and dead code elimination. - -if (typeof _ !== 'undefined') - throw new Error("If you have Underscore, don't use Microscore"); - -_ = {}; - -var hasOwnProperty = Object.prototype.hasOwnProperty; -var objectToString = Object.prototype.toString; - -// Doesn't support more than two arguments (more than one "source" -// object). -_.extend = function (tgt, src) { - for (var k in src) { - if (hasOwnProperty.call(src, k)) - tgt[k] = src[k]; - } - return tgt; -}; - -_.has = function (obj, key) { - return hasOwnProperty.call(obj, key); -}; - -// Returns a copy of `array` with falsy elements removed. -_.compact = function (array) { - var result = []; - for (var i = 0; i < array.length; i++) { - var item = array[i]; - if (item) - result.push(item); - } - return result; -}; - -// Returns whether `array` contains an element that is -// `=== item`. -_.contains = function (array, item) { - for (var i = 0; i < array.length; i++) { - if (array[i] === item) - return true; - } - return false; -}; - -// Returns `array` filtered to exclude elements that are -// `=== item`. Similar to `_.without`. -_.without = function (array, item) { - var result = []; - for (var i = 0; i < array.length; i++) { - var x = array[i]; - if (x !== item) - result.push(x); - } - return result; -}; - -// Assembles an array by calling `func(oldElement, index)` -// on each element of `array`. Assumes argument is an array. -_.map = function (array, func) { - var result = new Array(array.length); - for (var i = 0; i < array.length; i++) { - result[i] = func(array[i], i); - } - return result; -}; - -// Given an array: Calls `func(element, index)` on each element of -// `array`. -// -// Given an object: Calls `func(value, key)` on each key/value of -// `obj`. -// -// Only REAL arrays are treated as arrays. No Arguments objects, jQuery -// objects, etc. This may be relaxed to the standard Meteor approach -// if it is too constraining. -// -// Doesn't accept `null` as first argument. Doesn't delegate to built-in -// `forEach` (which is generally not faster anyway because it calls -// across the C/JS boundary). Doesn't mess with JavaScript's built-in -// behavior if keys are added or removed during iteration (i.e. may -// or may not visit them). - -_.each = function (arrayOrObject, func) { - if (objectToString.call(arrayOrObject) === '[object Array]') { - var array = arrayOrObject; - for (var i = 0; i < array.length; i++) { - func(array[i], i); - } - } else { - var obj = arrayOrObject; - for (var key in obj) { - if (_.has(obj, key)) - func(obj[key], key); - } - } -}; - -_.bind = function (f, context) { - return function () { - return f.apply(target, context); - }; -}; diff --git a/packages/blaze/package.js b/packages/blaze/package.js deleted file mode 100644 index 9bcacbb5bd..0000000000 --- a/packages/blaze/package.js +++ /dev/null @@ -1,55 +0,0 @@ -Package.describe({ - summary: "Meteor Reactive Templating library", - version: '2.1.8' -}); - -Package.onUse(function (api) { - api.export(['Blaze', 'UI', 'Handlebars']); - api.use('jquery'); // should be a weak dep, by having multiple "DOM backends" - api.use('tracker'); - api.use('check'); - api.use('underscore'); // only the subset in microscore.js - api.use('htmljs'); - api.imply('htmljs'); - api.use('observe-sequence'); - api.use('reactive-var'); - - api.addFiles([ - 'preamble.js' - ]); - - // client-only files - api.addFiles([ - 'dombackend.js', - 'domrange.js', - 'events.js', - 'attrs.js', - 'materializer.js' - ], 'client'); - - // client and server - api.addFiles([ - 'exceptions.js', - 'view.js', - 'builtins.js', - 'lookup.js', - 'template.js', - 'backcompat.js' - ]); -}); - -Package.onTest(function (api) { - api.use('tinytest'); - api.use('jquery'); // strong dependency, for testing jQuery backend - api.use('blaze'); - api.use('test-helpers'); - api.use('underscore'); - api.use('blaze-tools'); // for BlazeTools.toJS - api.use('html-tools'); - api.use('reactive-var'); - api.use('tracker'); - api.use('templating'); - - api.addFiles('view_tests.js'); - api.addFiles('render_tests.js', 'client'); -}); diff --git a/packages/blaze/preamble.js b/packages/blaze/preamble.js deleted file mode 100644 index aba9384a76..0000000000 --- a/packages/blaze/preamble.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @namespace Blaze - * @summary The namespace for all Blaze-related methods and classes. - */ -Blaze = {}; - -// Utility to HTML-escape a string. Included for legacy reasons. -Blaze._escape = (function() { - var escape_map = { - "<": "<", - ">": ">", - '"': """, - "'": "'", - "`": "`", /* IE allows backtick-delimited attributes?? */ - "&": "&" - }; - var escape_one = function(c) { - return escape_map[c]; - }; - - return function (x) { - return x.replace(/[&<>"'`]/g, escape_one); - }; -})(); - -Blaze._warn = function (msg) { - msg = 'Warning: ' + msg; - - if ((typeof console !== 'undefined') && console.warn) { - console.warn(msg); - } -}; diff --git a/packages/blaze/render_tests.js b/packages/blaze/render_tests.js deleted file mode 100644 index bccc001716..0000000000 --- a/packages/blaze/render_tests.js +++ /dev/null @@ -1,688 +0,0 @@ -var toCode = BlazeTools.toJS; - -var P = HTML.P; -var CharRef = HTML.CharRef; -var DIV = HTML.DIV; -var Comment = HTML.Comment; -var BR = HTML.BR; -var A = HTML.A; -var UL = HTML.UL; -var LI = HTML.LI; -var SPAN = HTML.SPAN; -var HR = HTML.HR; -var TEXTAREA = HTML.TEXTAREA; -var INPUT = HTML.INPUT; - -var materialize = function (content, parent) { - var func = content; - if (typeof content !== 'function') { - func = function () { - return content; - }; - } - Blaze.render(func, parent); -}; - -var toHTML = Blaze.toHTML; - -Tinytest.add("blaze - render - basic", function (test) { - var run = function (input, expectedInnerHTML, expectedHTML, expectedCode) { - var div = document.createElement("DIV"); - materialize(input, div); - test.equal(canonicalizeHtml(div.innerHTML), expectedInnerHTML); - test.equal(toHTML(input), expectedHTML); - if (typeof expectedCode !== 'undefined') - test.equal(toCode(input), expectedCode); - }; - - run(P('Hello'), - '

Hello

', - '

Hello

', - 'HTML.P("Hello")'); - - run([], '', '', '[]'); - run([null, null], '', '', '[null, null]'); - - // Test crazy character references - - // `𝕫` is "Mathematical double-struck small z" a.k.a. "open-face z" - run(P(CharRef({html: '𝕫', str: '\ud835\udd6b'})), - '

\ud835\udd6b

', - '

𝕫

', - 'HTML.P(HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}))'); - - run(P({id: CharRef({html: '𝕫', str: '\ud835\udd6b'})}, 'Hello'), - '

Hello

', - '

Hello

', - 'HTML.P({id: HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"})}, "Hello")'); - - run(P({id: [CharRef({html: '𝕫', str: '\ud835\udd6b'}), '!']}, 'Hello'), - '

Hello

', - '

Hello

', - 'HTML.P({id: [HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}), "!"]}, "Hello")'); - - // Test comments - - run(DIV(Comment('Test')), - '
', // our innerHTML-canonicalization function kills comment contents - '
', - 'HTML.DIV(HTML.Comment("Test"))'); - - // Test arrays - - run([P('Hello'), P('World')], - '

Hello

World

', - '

Hello

World

', - '[HTML.P("Hello"), HTML.P("World")]'); - - // Test slightly more complicated structure - - run(DIV({'class': 'foo'}, UL(LI(P(A({href: '#one'}, 'One'))), - LI(P('Two', BR(), 'Three')))), - '
', - '
', - 'HTML.DIV({"class": "foo"}, HTML.UL(HTML.LI(HTML.P(HTML.A({href: "#one"}, "One"))), HTML.LI(HTML.P("Two", HTML.BR(), "Three"))))'); - - - // Test nully attributes - run(BR({x: null, - y: [[], []], - a: [['']]}), - '
', - '
', - 'HTML.BR({a: [[""]]})'); - - run(BR({ - x: function () { return Blaze.View(function () { return Blaze.View(function () { return []; }); }); }, - a: function () { return Blaze.View(function () { return Blaze.View(function () { return ''; }); }); }}), - '
', - '
'); -}); - -// test that we correctly update the 'value' property on input fields -// rather than the 'value' attribute. the 'value' attribute only sets -// the initial value. -Tinytest.add("blaze - render - input - value", function (test) { - var R = ReactiveVar("hello"); - var div = document.createElement("DIV"); - materialize(INPUT({value: function () { return R.get(); }}), div); - var inputEl = div.querySelector('input'); - test.equal(inputEl.value, "hello"); - inputEl.value = "goodbye"; - R.set("hola"); - Tracker.flush(); - test.equal(inputEl.value, "hola"); -}); - -// test that we correctly update the 'checked' property rather than -// the 'checked' attribute on input fields of type 'checkbox'. the -// 'checked' attribute only sets the initial value. -Tinytest.add("blaze - render - input - checked", function (test) { - var R = ReactiveVar(null); - var div = document.createElement("DIV"); - materialize(INPUT({type: "checkbox", checked: function () { return R.get(); }}), div); - var inputEl = div.querySelector('input'); - test.equal(inputEl.checked, false); - inputEl.checked = true; - - R.set("checked"); - Tracker.flush(); - R.set(null); - Tracker.flush(); - test.equal(inputEl.checked, false); -}); - -Tinytest.add("blaze - render - textarea", function (test) { - var run = function (optNode, text, html, code) { - if (typeof optNode === 'string') { - // called with args (text, html, code) - code = html; - html = text; - text = optNode; - optNode = null; - } - var div = document.createElement("DIV"); - var node = TEXTAREA({value: optNode || text}); - materialize(node, div); - - var value = div.querySelector('textarea').value; - value = value.replace(/\r\n/g, "\n"); // IE8 substitutes \n with \r\n - test.equal(value, text); - - test.equal(toHTML(node), html); - if (typeof code === 'string') - test.equal(toCode(node), code); - }; - - run('Hello', - '', - 'HTML.TEXTAREA({value: "Hello"})'); - - run('\nHello', - '', - 'HTML.TEXTAREA({value: "\\nHello"})'); - - run('', - '', - 'HTML.TEXTAREA({value: ""})'); - - run(CharRef({html: '&', str: '&'}), - '&', - '', - 'HTML.TEXTAREA({value: HTML.CharRef({html: "&", str: "&"})})'); - - run(function () { - return ['a', Blaze.View(function () { return 'b'; }), 'c']; - }, - 'abc', - ''); - - // test that reactivity of textarea "value" attribute works... - (function () { - var R = ReactiveVar('one'); - var div = document.createElement("DIV"); - var node = TEXTAREA({value: function () { - return Blaze.View(function () { - return R.get(); - }); - }}); - materialize(node, div); - var textarea = div.querySelector('textarea'); - test.equal(textarea.value, 'one'); - R.set('two'); - Tracker.flush(); - test.equal(textarea.value, 'two'); - })(); - - // ... while "content" reactivity simply doesn't update - // (but doesn't throw either) - (function () { - var R = ReactiveVar('one'); - var div = document.createElement("DIV"); - var node = TEXTAREA([Blaze.View(function () { - return R.get(); - })]); - materialize(node, div); - var textarea = div.querySelector('textarea'); - test.equal(textarea.value, 'one'); - R.set('two'); - Tracker.flush({_throwFirstError: true}); - test.equal(textarea.value, 'one'); - })(); -}); - -Tinytest.add("blaze - render - view isolation", function (test) { - - // Reactively change a text node - (function () { - var R = ReactiveVar('Hello'); - var test1 = function () { - return P(Blaze.View(function () { return R.get(); })); - }; - - test.equal(toHTML(test1()), '

Hello

'); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "

Hello

"); - - R.set('World'); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "

World

"); - })(); - - // Reactively change an array of text nodes - (function () { - var R = ReactiveVar(['Hello', ' World']); - var test1 = function () { - return P(Blaze.View(function () { return R.get(); })); - }; - - test.equal(toHTML(test1()), '

Hello World

'); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "

Hello World

"); - - R.set(['Goodbye', ' World']); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "

Goodbye World

"); - })(); - -}); - -// IE strips malformed styles like "bar::d" from the `style` -// attribute. We detect this to adjust expectations for the StyleHandler -// test below. -var malformedStylesAllowed = function () { - var div = document.createElement("div"); - div.setAttribute("style", "bar::d;"); - return (div.getAttribute("style") === "bar::d;"); -}; - -Tinytest.add("blaze - render - view GC", function (test) { - // test that removing parent element removes listeners and stops autoruns. - (function () { - var R = ReactiveVar('Hello'); - var test1 = P(Blaze.View(function () { return R.get(); })); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "

Hello

"); - - R.set('World'); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "

World

"); - - test.equal(R._numListeners(), 1); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - - R.set('Steve'); - Tracker.flush(); - // should not have changed: - test.equal(canonicalizeHtml(div.innerHTML), "

World

"); - })(); - -}); - -Tinytest.add("blaze - render - reactive attributes", function (test) { - (function () { - var R = ReactiveVar({'class': ['david gre', CharRef({html: 'ë', str: '\u00eb'}), 'nspan'], - id: 'foo'}); - - var spanFunc = function () { - return SPAN(HTML.Attrs( - function () { return R.get(); })); - }; - - test.equal(Blaze.toHTML(spanFunc()), - ''); - - test.equal(R._numListeners(), 0); - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - test.equal(R._numListeners(), 1); - - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - span.className += ' blah'; // change the element's class outside of Blaze. this simulates what a jQuery could do - - R.set({'class': 'david smith', id: 'bar'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R._numListeners(), 1); - - R.set({}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R._numListeners(), 1); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - })(); - - // Test styles. - (function () { - // Test the case where there is a semicolon in the css attribute. - var R = ReactiveVar({'style': 'foo: "a;aa"; bar: b;', - id: 'foo'}); - - var spanFunc = function () { - return SPAN(HTML.Attrs(function () { return R.get(); })); - }; - - test.equal(Blaze.toHTML(spanFunc()), ''); - - test.equal(R._numListeners(), 0); - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - test.equal(R._numListeners(), 1); - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - - span.setAttribute('style', span.getAttribute('style') + '; jquery-style: hidden'); - - R.set({'style': 'foo: "a;zz;aa";', id: 'bar'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML, true), ''); - test.equal(R._numListeners(), 1); - - R.set({}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R._numListeners(), 1); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - })(); - - // Test that identical styles are successfully overwritten. - (function () { - - var R = ReactiveVar({'style': 'foo: a;'}); - - var spanFunc = function () { - return SPAN(HTML.Attrs(function () { return R.get(); })); - }; - - var div = document.createElement("DIV"); - document.body.appendChild(div); - Blaze.render(spanFunc, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - span.setAttribute("style", 'foo: b;'); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({'style': 'foo: c;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - // test malformed styles - different expectations in IE (which - // strips malformed styles) from other browsers - R.set({'style': 'foo: a; bar::d;:e; baz: c;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), - malformedStylesAllowed() ? - '' : - ''); - - // Test strange styles - R.set({'style': ' foo: c; constructor: a; __proto__: b;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({'style': 'foo: bar;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - })(); - - // Test `null`, `undefined`, and `[]` attributes - (function () { - var R = ReactiveVar({id: 'foo', - aaa: null, - bbb: undefined, - ccc: [], - ddd: [null], - eee: [undefined], - fff: [[]], - ggg: ['x', ['y', ['z']]]}); - - var spanFunc = function () { - return SPAN(HTML.Attrs( - function () { return R.get(); })); - }; - - test.equal(Blaze.toHTML(spanFunc()), ''); - test.equal(toCode(SPAN(R.get())), - 'HTML.SPAN({id: "foo", ggg: ["x", ["y", ["z"]]]})'); - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - - test.equal(canonicalizeHtml(div.innerHTML), ''); - R.set({id: 'foo', ggg: [[], [], []]}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({id: 'foo', ggg: null}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({id: 'foo', ggg: ''}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - })(); -}); - -Tinytest.add("blaze - render - templates and views", function (test) { - (function () { - var counter = 1; - var buf = []; - - var myTemplate = Blaze.Template( - 'myTemplate', - function () { - return [String(this.number), - (this.number < 3 ? makeView() : HR())]; - }); - - myTemplate.constructView = function (number) { - var view = Template.prototype.constructView.call(this); - view.number = number; - return view; - }; - - myTemplate.created = function () { - test.isFalse(Tracker.active); - var view = this.view; - var parent = Blaze.getView(view, 'myTemplate'); - if (parent) { - buf.push('parent of ' + view.number + ' is ' + - parent.number); - } - - buf.push('created ' + Template.currentData()); - }; - - myTemplate.onRendered(function () { - test.isFalse(Tracker.active); - var nodeDescr = function (node) { - if (node.nodeType === 8) // comment - return ''; - if (node.nodeType === 3) // text - return node.nodeValue; - - return node.nodeName; - }; - - var view = this.view; - var start = view.firstNode(); - var end = view.lastNode(); - // skip marker nodes - while (start !== end && ! nodeDescr(start)) - start = start.nextSibling; - while (end !== start && ! nodeDescr(end)) - end = end.previousSibling; - - buf.push('dom-' + Template.currentData() + - ' is ' + nodeDescr(start) +'..' + - nodeDescr(end)); - }); - - myTemplate.onDestroyed(function () { - test.isFalse(Tracker.active); - buf.push('destroyed ' + Template.currentData()); - }); - - var makeView = function () { - var number = counter++; - return Blaze.With(number, function () { - return myTemplate.constructView(number); - }); - }; - - var div = document.createElement("DIV"); - - Blaze.render(makeView, div); - buf.push('---flush---'); - Tracker.flush(); - test.equal(buf, ['created 1', - 'parent of 2 is 1', - 'created 2', - 'parent of 3 is 2', - 'created 3', - '---flush---', - // (proper order for these has not be thought out:) - 'dom-3 is 3..HR', - 'dom-2 is 2..HR', - 'dom-1 is 1..HR']); - - test.equal(canonicalizeHtml(div.innerHTML), '123
'); - - buf.length = 0; - $(div).remove(); - buf.sort(); - test.equal(buf, ['destroyed 1', 'destroyed 2', 'destroyed 3']); - - // Now use toHTML. Should still get most of the callbacks (not `rendered`). - - buf.length = 0; - counter = 1; - - var html = Blaze.toHTML(makeView()); - - test.equal(buf, ['created 1', - 'parent of 2 is 1', - 'created 2', - 'parent of 3 is 2', - 'created 3', - 'destroyed 3', - 'destroyed 2', - 'destroyed 1']); - - test.equal(html, '123
'); - })(); -}); - -Tinytest.add("blaze - render - findAll", function (test) { - var found = null; - var $found = null; - - var myTemplate = new Template( - 'findAllTest', - function() { - return DIV([P('first'), P('second')]); - }); - myTemplate.rendered = function() { - found = this.findAll('p'); - $found = this.$('p'); - }; - - var div = document.createElement("DIV"); - - Blaze.render(myTemplate, div); - Tracker.flush(); - - test.equal(_.isArray(found), true); - test.equal(_.isArray($found), false); - test.equal(found.length, 2); - test.equal($found.length, 2); -}); - -Tinytest.add("blaze - render - reactive attributes 2", function (test) { - var R1 = ReactiveVar(['foo']); - var R2 = ReactiveVar(['bar']); - - var spanFunc = function () { - return SPAN(HTML.Attrs( - { blah: function () { return R1.get(); } }, - function () { return { blah: R2.get() }; })); - }; - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - var check = function (expected) { - test.equal(Blaze.toHTML(spanFunc()), expected); - test.equal(canonicalizeHtml(div.innerHTML), expected); - }; - check(''); - - test.equal(R1._numListeners(), 1); - test.equal(R2._numListeners(), 1); - - R2.set([[]]); - Tracker.flush(); - // We combine `['foo']` with what evaluates to `[[[]]]`, which is nully. - check(''); - - R2.set([['']]); - Tracker.flush(); - // We combine `['foo']` with what evaluates to `[[['']]]`, which is non-nully. - check(''); - - R2.set(null); - Tracker.flush(); - // We combine `['foo']` with `[null]`, which is nully. - check(''); - - R1.set([[], []]); - Tracker.flush(); - // We combine two nully values. - check(''); - - R1.set([[], ['foo']]); - Tracker.flush(); - check(''); - - // clean up - - $(div).remove(); - - test.equal(R1._numListeners(), 0); - test.equal(R2._numListeners(), 0); -}); - -Tinytest.add("blaze - render - SVG", function (test) { - if (! document.createElementNS) { - // IE 8 - return; - } - - var fillColor = ReactiveVar('red'); - var classes = ReactiveVar('one two'); - - var content = DIV({'class': 'container'}, HTML.SVG( - {width: 100, height: 100}, - HTML.CIRCLE({cx: 50, cy: 50, r: 40, - stroke: 'black', 'stroke-width': 3, - 'class': function () { return classes.get(); }, - fill: function () { return fillColor.get(); }}))); - - var div = document.createElement("DIV"); - materialize(content, div); - - var circle = div.querySelector('.container > svg > circle'); - test.equal(circle.getAttribute('fill'), 'red'); - test.equal(circle.className.baseVal, 'one two'); - - fillColor.set('green'); - classes.set('two three'); - Tracker.flush(); - test.equal(circle.getAttribute('fill'), 'green'); - test.equal(circle.className.baseVal, 'two three'); - - test.equal(circle.nodeName, 'circle'); - test.equal(circle.namespaceURI, "http://www.w3.org/2000/svg"); - test.equal(circle.parentNode.namespaceURI, "http://www.w3.org/2000/svg"); -}); - -Tinytest.add("ui - attributes", function (test) { - var SPAN = HTML.SPAN; - var amp = HTML.CharRef({html: '&', str: '&'}); - - test.equal(HTML.toHTML(SPAN({title: ['M', amp, 'Ms']}, 'M', amp, 'M candies')), - 'M&M candies'); -}); diff --git a/packages/blaze/template.js b/packages/blaze/template.js deleted file mode 100644 index 4a6b5842d8..0000000000 --- a/packages/blaze/template.js +++ /dev/null @@ -1,565 +0,0 @@ -// [new] Blaze.Template([viewName], renderFunction) -// -// `Blaze.Template` is the class of templates, like `Template.foo` in -// Meteor, which is `instanceof Template`. -// -// `viewKind` is a string that looks like "Template.foo" for templates -// defined by the compiler. - -/** - * @class - * @summary Constructor for a Template, which is used to construct Views with particular name and content. - * @locus Client - * @param {String} [viewName] Optional. A name for Views constructed by this Template. See [`view.name`](#view_name). - * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content). This function is used as the `renderFunction` for Views constructed by this Template. - */ -Blaze.Template = function (viewName, renderFunction) { - if (! (this instanceof Blaze.Template)) - // called without `new` - return new Blaze.Template(viewName, renderFunction); - - if (typeof viewName === 'function') { - // omitted "viewName" argument - renderFunction = viewName; - viewName = ''; - } - if (typeof viewName !== 'string') - throw new Error("viewName must be a String (or omitted)"); - if (typeof renderFunction !== 'function') - throw new Error("renderFunction must be a function"); - - this.viewName = viewName; - this.renderFunction = renderFunction; - - this.__helpers = new HelperMap; - this.__eventMaps = []; - - this._callbacks = { - created: [], - rendered: [], - destroyed: [] - }; -}; -var Template = Blaze.Template; - -var HelperMap = function () {}; -HelperMap.prototype.get = function (name) { - return this[' '+name]; -}; -HelperMap.prototype.set = function (name, helper) { - this[' '+name] = helper; -}; -HelperMap.prototype.has = function (name) { - return (' '+name) in this; -}; - -/** - * @summary Returns true if `value` is a template object like `Template.myTemplate`. - * @locus Client - * @param {Any} value The value to test. - */ -Blaze.isTemplate = function (t) { - return (t instanceof Blaze.Template); -}; - -/** - * @name onCreated - * @instance - * @memberOf Template - * @summary Register a function to be called when an instance of this template is created. - * @param {Function} callback A function to be added as a callback. - * @locus Client - * @importFromPackage templating - */ -Template.prototype.onCreated = function (cb) { - this._callbacks.created.push(cb); -}; - -/** - * @name onRendered - * @instance - * @memberOf Template - * @summary Register a function to be called when an instance of this template is inserted into the DOM. - * @param {Function} callback A function to be added as a callback. - * @locus Client - * @importFromPackage templating - */ -Template.prototype.onRendered = function (cb) { - this._callbacks.rendered.push(cb); -}; - -/** - * @name onDestroyed - * @instance - * @memberOf Template - * @summary Register a function to be called when an instance of this template is removed from the DOM and destroyed. - * @param {Function} callback A function to be added as a callback. - * @locus Client - * @importFromPackage templating - */ -Template.prototype.onDestroyed = function (cb) { - this._callbacks.destroyed.push(cb); -}; - -Template.prototype._getCallbacks = function (which) { - var self = this; - var callbacks = self[which] ? [self[which]] : []; - // Fire all callbacks added with the new API (Template.onRendered()) - // as well as the old-style callback (e.g. Template.rendered) for - // backwards-compatibility. - callbacks = callbacks.concat(self._callbacks[which]); - return callbacks; -}; - -var fireCallbacks = function (callbacks, template) { - Template._withTemplateInstanceFunc( - function () { return template; }, - function () { - for (var i = 0, N = callbacks.length; i < N; i++) { - callbacks[i].call(template); - } - }); -}; - -Template.prototype.constructView = function (contentFunc, elseFunc) { - var self = this; - var view = Blaze.View(self.viewName, self.renderFunction); - view.template = self; - - view.templateContentBlock = ( - contentFunc ? new Template('(contentBlock)', contentFunc) : null); - view.templateElseBlock = ( - elseFunc ? new Template('(elseBlock)', elseFunc) : null); - - if (self.__eventMaps || typeof self.events === 'object') { - view._onViewRendered(function () { - if (view.renderCount !== 1) - return; - - if (! self.__eventMaps.length && typeof self.events === "object") { - // Provide limited back-compat support for `.events = {...}` - // syntax. Pass `template.events` to the original `.events(...)` - // function. This code must run only once per template, in - // order to not bind the handlers more than once, which is - // ensured by the fact that we only do this when `__eventMaps` - // is falsy, and we cause it to be set now. - Template.prototype.events.call(self, self.events); - } - - _.each(self.__eventMaps, function (m) { - Blaze._addEventMap(view, m, view); - }); - }); - } - - view._templateInstance = new Blaze.TemplateInstance(view); - view.templateInstance = function () { - // Update data, firstNode, and lastNode, and return the TemplateInstance - // object. - var inst = view._templateInstance; - - /** - * @instance - * @memberOf Blaze.TemplateInstance - * @name data - * @summary The data context of this instance's latest invocation. - * @locus Client - */ - inst.data = Blaze.getData(view); - - if (view._domrange && !view.isDestroyed) { - inst.firstNode = view._domrange.firstNode(); - inst.lastNode = view._domrange.lastNode(); - } else { - // on 'created' or 'destroyed' callbacks we don't have a DomRange - inst.firstNode = null; - inst.lastNode = null; - } - - return inst; - }; - - /** - * @name created - * @instance - * @memberOf Template - * @summary Provide a callback when an instance of a template is created. - * @locus Client - * @deprecated in 1.1 - */ - // To avoid situations when new callbacks are added in between view - // instantiation and event being fired, decide on all callbacks to fire - // immediately and then fire them on the event. - var createdCallbacks = self._getCallbacks('created'); - view.onViewCreated(function () { - fireCallbacks(createdCallbacks, view.templateInstance()); - }); - - /** - * @name rendered - * @instance - * @memberOf Template - * @summary Provide a callback when an instance of a template is rendered. - * @locus Client - * @deprecated in 1.1 - */ - var renderedCallbacks = self._getCallbacks('rendered'); - view.onViewReady(function () { - fireCallbacks(renderedCallbacks, view.templateInstance()); - }); - - /** - * @name destroyed - * @instance - * @memberOf Template - * @summary Provide a callback when an instance of a template is destroyed. - * @locus Client - * @deprecated in 1.1 - */ - var destroyedCallbacks = self._getCallbacks('destroyed'); - view.onViewDestroyed(function () { - fireCallbacks(destroyedCallbacks, view.templateInstance()); - }); - - return view; -}; - -/** - * @class - * @summary The class for template instances - * @param {Blaze.View} view - * @instanceName template - */ -Blaze.TemplateInstance = function (view) { - if (! (this instanceof Blaze.TemplateInstance)) - // called without `new` - return new Blaze.TemplateInstance(view); - - if (! (view instanceof Blaze.View)) - throw new Error("View required"); - - view._templateInstance = this; - - /** - * @name view - * @memberOf Blaze.TemplateInstance - * @instance - * @summary The [View](#blaze_view) object for this invocation of the template. - * @locus Client - * @type {Blaze.View} - */ - this.view = view; - this.data = null; - - /** - * @name firstNode - * @memberOf Blaze.TemplateInstance - * @instance - * @summary The first top-level DOM node in this template instance. - * @locus Client - * @type {DOMNode} - */ - this.firstNode = null; - - /** - * @name lastNode - * @memberOf Blaze.TemplateInstance - * @instance - * @summary The last top-level DOM node in this template instance. - * @locus Client - * @type {DOMNode} - */ - this.lastNode = null; - - // This dependency is used to identify state transitions in - // _subscriptionHandles which could cause the result of - // TemplateInstance#subscriptionsReady to change. Basically this is triggered - // whenever a new subscription handle is added or when a subscription handle - // is removed and they are not ready. - this._allSubsReadyDep = new Tracker.Dependency(); - this._allSubsReady = false; - - this._subscriptionHandles = {}; -}; - -/** - * @summary Find all elements matching `selector` in this template instance, and return them as a JQuery object. - * @locus Client - * @param {String} selector The CSS selector to match, scoped to the template contents. - * @returns {DOMNode[]} - */ -Blaze.TemplateInstance.prototype.$ = function (selector) { - var view = this.view; - if (! view._domrange) - throw new Error("Can't use $ on template instance with no DOM"); - return view._domrange.$(selector); -}; - -/** - * @summary Find all elements matching `selector` in this template instance. - * @locus Client - * @param {String} selector The CSS selector to match, scoped to the template contents. - * @returns {DOMElement[]} - */ -Blaze.TemplateInstance.prototype.findAll = function (selector) { - return Array.prototype.slice.call(this.$(selector)); -}; - -/** - * @summary Find one element matching `selector` in this template instance. - * @locus Client - * @param {String} selector The CSS selector to match, scoped to the template contents. - * @returns {DOMElement} - */ -Blaze.TemplateInstance.prototype.find = function (selector) { - var result = this.$(selector); - return result[0] || null; -}; - -/** - * @summary A version of [Tracker.autorun](#tracker_autorun) that is stopped when the template is destroyed. - * @locus Client - * @param {Function} runFunc The function to run. It receives one argument: a Tracker.Computation object. - */ -Blaze.TemplateInstance.prototype.autorun = function (f) { - return this.view.autorun(f); -}; - -/** - * @summary A version of [Meteor.subscribe](#meteor_subscribe) that is stopped - * when the template is destroyed. - * @return {SubscriptionHandle} The subscription handle to the newly made - * subscription. Call `handle.stop()` to manually stop the subscription, or - * `handle.ready()` to find out if this particular subscription has loaded all - * of its inital data. - * @locus Client - * @param {String} name Name of the subscription. Matches the name of the - * server's `publish()` call. - * @param {Any} [arg1,arg2...] Optional arguments passed to publisher function - * on server. - * @param {Function|Object} [options] If a function is passed instead of an - * object, it is interpreted as an `onReady` callback. - * @param {Function} [options.onReady] Passed to [`Meteor.subscribe`](#meteor_subscribe). - * @param {Function} [options.onStop] Passed to [`Meteor.subscribe`](#meteor_subscribe). - * @param {DDP.Connection} [options.connection] The connection on which to make the - * subscription. - */ -Blaze.TemplateInstance.prototype.subscribe = function (/* arguments */) { - var self = this; - - var subHandles = self._subscriptionHandles; - var args = _.toArray(arguments); - - // Duplicate logic from Meteor.subscribe - var options = {}; - if (args.length) { - var lastParam = _.last(args); - - // Match pattern to check if the last arg is an options argument - var lastParamOptionsPattern = { - onReady: Match.Optional(Function), - // XXX COMPAT WITH 1.0.3.1 onError used to exist, but now we use - // onStop with an error callback instead. - onError: Match.Optional(Function), - onStop: Match.Optional(Function), - connection: Match.Optional(Match.Any) - }; - - if (_.isFunction(lastParam)) { - options.onReady = args.pop(); - } else if (lastParam && ! _.isEmpty(lastParam) && Match.test(lastParam, lastParamOptionsPattern)) { - options = args.pop(); - } - } - - var subHandle; - var oldStopped = options.onStop; - options.onStop = function (error) { - // When the subscription is stopped, remove it from the set of tracked - // subscriptions to avoid this list growing without bound - delete subHandles[subHandle.subscriptionId]; - - // Removing a subscription can only change the result of subscriptionsReady - // if we are not ready (that subscription could be the one blocking us being - // ready). - if (! self._allSubsReady) { - self._allSubsReadyDep.changed(); - } - - if (oldStopped) { - oldStopped(error); - } - }; - - var connection = options.connection; - var callbacks = _.pick(options, ["onReady", "onError", "onStop"]); - - // The callbacks are passed as the last item in the arguments array passed to - // View#subscribe - args.push(callbacks); - - // View#subscribe takes the connection as one of the options in the last - // argument - subHandle = self.view.subscribe.call(self.view, args, { - connection: connection - }); - - if (! _.has(subHandles, subHandle.subscriptionId)) { - subHandles[subHandle.subscriptionId] = subHandle; - - // Adding a new subscription will always cause us to transition from ready - // to not ready, but if we are already not ready then this can't make us - // ready. - if (self._allSubsReady) { - self._allSubsReadyDep.changed(); - } - } - - return subHandle; -}; - -/** - * @summary A reactive function that returns true when all of the subscriptions - * called with [this.subscribe](#TemplateInstance-subscribe) are ready. - * @return {Boolean} True if all subscriptions on this template instance are - * ready. - */ -Blaze.TemplateInstance.prototype.subscriptionsReady = function () { - this._allSubsReadyDep.depend(); - - this._allSubsReady = _.all(this._subscriptionHandles, function (handle) { - return handle.ready(); - }); - - return this._allSubsReady; -}; - -/** - * @summary Specify template helpers available to this template. - * @locus Client - * @param {Object} helpers Dictionary of helper functions by name. - * @importFromPackage templating - */ -Template.prototype.helpers = function (dict) { - if (! _.isObject(dict)) { - throw new Error("Helpers dictionary has to be an object"); - } - - for (var k in dict) - this.__helpers.set(k, dict[k]); -}; - -// Kind of like Blaze.currentView but for the template instance. -// This is a function, not a value -- so that not all helpers -// are implicitly dependent on the current template instance's `data` property, -// which would make them dependenct on the data context of the template -// inclusion. -Template._currentTemplateInstanceFunc = null; - -Template._withTemplateInstanceFunc = function (templateInstanceFunc, func) { - if (typeof func !== 'function') - throw new Error("Expected function, got: " + func); - var oldTmplInstanceFunc = Template._currentTemplateInstanceFunc; - try { - Template._currentTemplateInstanceFunc = templateInstanceFunc; - return func(); - } finally { - Template._currentTemplateInstanceFunc = oldTmplInstanceFunc; - } -}; - -/** - * @summary Specify event handlers for this template. - * @locus Client - * @param {EventMap} eventMap Event handlers to associate with this template. - * @importFromPackage templating - */ -Template.prototype.events = function (eventMap) { - if (! _.isObject(eventMap)) { - throw new Error("Event map has to be an object"); - } - - var template = this; - var eventMap2 = {}; - for (var k in eventMap) { - eventMap2[k] = (function (k, v) { - return function (event/*, ...*/) { - var view = this; // passed by EventAugmenter - var data = Blaze.getData(event.currentTarget); - if (data == null) - data = {}; - var args = Array.prototype.slice.call(arguments); - var tmplInstanceFunc = _.bind(view.templateInstance, view); - args.splice(1, 0, tmplInstanceFunc()); - - return Template._withTemplateInstanceFunc(tmplInstanceFunc, function () { - return v.apply(data, args); - }); - }; - })(k, eventMap[k]); - } - - template.__eventMaps.push(eventMap2); -}; - -/** - * @function - * @name instance - * @memberOf Template - * @summary The [template instance](#template_inst) corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, `null`. - * @locus Client - * @returns {Blaze.TemplateInstance} - * @importFromPackage templating - */ -Template.instance = function () { - return Template._currentTemplateInstanceFunc - && Template._currentTemplateInstanceFunc(); -}; - -// Note: Template.currentData() is documented to take zero arguments, -// while Blaze.getData takes up to one. - -/** - * @summary - * - * - Inside an `onCreated`, `onRendered`, or `onDestroyed` callback, returns - * the data context of the template. - * - Inside an event handler, returns the data context of the template on which - * this event handler was defined. - * - Inside a helper, returns the data context of the DOM node where the helper - * was used. - * - * Establishes a reactive dependency on the result. - * @locus Client - * @function - * @importFromPackage templating - */ -Template.currentData = Blaze.getData; - -/** - * @summary Accesses other data contexts that enclose the current data context. - * @locus Client - * @function - * @param {Integer} [numLevels] The number of levels beyond the current data context to look. Defaults to 1. - * @importFromPackage templating - */ -Template.parentData = Blaze._parentData; - -/** - * @summary Defines a [helper function](#template_helpers) which can be used from all templates. - * @locus Client - * @function - * @param {String} name The name of the helper function you are defining. - * @param {Function} function The helper function itself. - * @importFromPackage templating - */ -Template.registerHelper = Blaze.registerHelper; - -/** - * @summary Removes a global [helper function](#template_helpers). - * @locus Client - * @function - * @param {String} name The name of the helper function you are defining. - * @importFromPackage templating - */ -Template.deregisterHelper = Blaze.deregisterHelper; diff --git a/packages/blaze/view.js b/packages/blaze/view.js deleted file mode 100644 index 3a17d3487d..0000000000 --- a/packages/blaze/view.js +++ /dev/null @@ -1,900 +0,0 @@ -/// [new] Blaze.View([name], renderMethod) -/// -/// Blaze.View is the building block of reactive DOM. Views have -/// the following features: -/// -/// * lifecycle callbacks - Views are created, rendered, and destroyed, -/// and callbacks can be registered to fire when these things happen. -/// -/// * parent pointer - A View points to its parentView, which is the -/// View that caused it to be rendered. These pointers form a -/// hierarchy or tree of Views. -/// -/// * render() method - A View's render() method specifies the DOM -/// (or HTML) content of the View. If the method establishes -/// reactive dependencies, it may be re-run. -/// -/// * a DOMRange - If a View is rendered to DOM, its position and -/// extent in the DOM are tracked using a DOMRange object. -/// -/// When a View is constructed by calling Blaze.View, the View is -/// not yet considered "created." It doesn't have a parentView yet, -/// and no logic has been run to initialize the View. All real -/// work is deferred until at least creation time, when the onViewCreated -/// callbacks are fired, which happens when the View is "used" in -/// some way that requires it to be rendered. -/// -/// ...more lifecycle stuff -/// -/// `name` is an optional string tag identifying the View. The only -/// time it's used is when looking in the View tree for a View of a -/// particular name; for example, data contexts are stored on Views -/// of name "with". Names are also useful when debugging, so in -/// general it's good for functions that create Views to set the name. -/// Views associated with templates have names of the form "Template.foo". - -/** - * @class - * @summary Constructor for a View, which represents a reactive region of DOM. - * @locus Client - * @param {String} [name] Optional. A name for this type of View. See [`view.name`](#view_name). - * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content). In this function, `this` is bound to the View. - */ -Blaze.View = function (name, render) { - if (! (this instanceof Blaze.View)) - // called without `new` - return new Blaze.View(name, render); - - if (typeof name === 'function') { - // omitted "name" argument - render = name; - name = ''; - } - this.name = name; - this._render = render; - - this._callbacks = { - created: null, - rendered: null, - destroyed: null - }; - - // Setting all properties here is good for readability, - // and also may help Chrome optimize the code by keeping - // the View object from changing shape too much. - this.isCreated = false; - this._isCreatedForExpansion = false; - this.isRendered = false; - this._isAttached = false; - this.isDestroyed = false; - this._isInRender = false; - this.parentView = null; - this._domrange = null; - // This flag is normally set to false except for the cases when view's parent - // was generated as part of expanding some syntactic sugar expressions or - // methods. - // Ex.: Blaze.renderWithData is an equivalent to creating a view with regular - // Blaze.render and wrapping it into {{#with data}}{{/with}} view. Since the - // users don't know anything about these generated parent views, Blaze needs - // this information to be available on views to make smarter decisions. For - // example: removing the generated parent view with the view on Blaze.remove. - this._hasGeneratedParent = false; - // Bindings accessible to children views (via view.lookup('name')) within the - // closest template view. - this._scopeBindings = {}; - - this.renderCount = 0; -}; - -Blaze.View.prototype._render = function () { return null; }; - -Blaze.View.prototype.onViewCreated = function (cb) { - this._callbacks.created = this._callbacks.created || []; - this._callbacks.created.push(cb); -}; - -Blaze.View.prototype._onViewRendered = function (cb) { - this._callbacks.rendered = this._callbacks.rendered || []; - this._callbacks.rendered.push(cb); -}; - -Blaze.View.prototype.onViewReady = function (cb) { - var self = this; - var fire = function () { - Tracker.afterFlush(function () { - if (! self.isDestroyed) { - Blaze._withCurrentView(self, function () { - cb.call(self); - }); - } - }); - }; - self._onViewRendered(function onViewRendered() { - if (self.isDestroyed) - return; - if (! self._domrange.attached) - self._domrange.onAttached(fire); - else - fire(); - }); -}; - -Blaze.View.prototype.onViewDestroyed = function (cb) { - this._callbacks.destroyed = this._callbacks.destroyed || []; - this._callbacks.destroyed.push(cb); -}; -Blaze.View.prototype.removeViewDestroyedListener = function (cb) { - var destroyed = this._callbacks.destroyed; - if (! destroyed) - return; - var index = _.lastIndexOf(destroyed, cb); - if (index !== -1) { - // XXX You'd think the right thing to do would be splice, but _fireCallbacks - // gets sad if you remove callbacks while iterating over the list. Should - // change this to use callback-hook or EventEmitter or something else that - // properly supports removal. - destroyed[index] = null; - } -}; - -/// View#autorun(func) -/// -/// Sets up a Tracker autorun that is "scoped" to this View in two -/// important ways: 1) Blaze.currentView is automatically set -/// on every re-run, and 2) the autorun is stopped when the -/// View is destroyed. As with Tracker.autorun, the first run of -/// the function is immediate, and a Computation object that can -/// be used to stop the autorun is returned. -/// -/// View#autorun is meant to be called from View callbacks like -/// onViewCreated, or from outside the rendering process. It may not -/// be called before the onViewCreated callbacks are fired (too early), -/// or from a render() method (too confusing). -/// -/// Typically, autoruns that update the state -/// of the View (as in Blaze.With) should be started from an onViewCreated -/// callback. Autoruns that update the DOM should be started -/// from either onViewCreated (guarded against the absence of -/// view._domrange), or onViewReady. -Blaze.View.prototype.autorun = function (f, _inViewScope, displayName) { - var self = this; - - // The restrictions on when View#autorun can be called are in order - // to avoid bad patterns, like creating a Blaze.View and immediately - // calling autorun on it. A freshly created View is not ready to - // have logic run on it; it doesn't have a parentView, for example. - // It's when the View is materialized or expanded that the onViewCreated - // handlers are fired and the View starts up. - // - // Letting the render() method call `this.autorun()` is problematic - // because of re-render. The best we can do is to stop the old - // autorun and start a new one for each render, but that's a pattern - // we try to avoid internally because it leads to helpers being - // called extra times, in the case where the autorun causes the - // view to re-render (and thus the autorun to be torn down and a - // new one established). - // - // We could lift these restrictions in various ways. One interesting - // idea is to allow you to call `view.autorun` after instantiating - // `view`, and automatically wrap it in `view.onViewCreated`, deferring - // the autorun so that it starts at an appropriate time. However, - // then we can't return the Computation object to the caller, because - // it doesn't exist yet. - if (! self.isCreated) { - throw new Error("View#autorun must be called from the created callback at the earliest"); - } - if (this._isInRender) { - throw new Error("Can't call View#autorun from inside render(); try calling it from the created or rendered callback"); - } - if (Tracker.active) { - throw new Error("Can't call View#autorun from a Tracker Computation; try calling it from the created or rendered callback"); - } - - var templateInstanceFunc = Blaze.Template._currentTemplateInstanceFunc; - - var func = function viewAutorun(c) { - return Blaze._withCurrentView(_inViewScope || self, function () { - return Blaze.Template._withTemplateInstanceFunc( - templateInstanceFunc, function () { - return f.call(self, c); - }); - }); - }; - - // Give the autorun function a better name for debugging and profiling. - // The `displayName` property is not part of the spec but browsers like Chrome - // and Firefox prefer it in debuggers over the name function was declared by. - func.displayName = - (self.name || 'anonymous') + ':' + (displayName || 'anonymous'); - var comp = Tracker.autorun(func); - - var stopComputation = function () { comp.stop(); }; - self.onViewDestroyed(stopComputation); - comp.onStop(function () { - self.removeViewDestroyedListener(stopComputation); - }); - - return comp; -}; - -Blaze.View.prototype._errorIfShouldntCallSubscribe = function () { - var self = this; - - if (! self.isCreated) { - throw new Error("View#subscribe must be called from the created callback at the earliest"); - } - if (self._isInRender) { - throw new Error("Can't call View#subscribe from inside render(); try calling it from the created or rendered callback"); - } - if (self.isDestroyed) { - throw new Error("Can't call View#subscribe from inside the destroyed callback, try calling it inside created or rendered."); - } -}; - -/** - * Just like Blaze.View#autorun, but with Meteor.subscribe instead of - * Tracker.autorun. Stop the subscription when the view is destroyed. - * @return {SubscriptionHandle} A handle to the subscription so that you can - * see if it is ready, or stop it manually - */ -Blaze.View.prototype.subscribe = function (args, options) { - var self = this; - options = options || {}; - - self._errorIfShouldntCallSubscribe(); - - var subHandle; - if (options.connection) { - subHandle = options.connection.subscribe.apply(options.connection, args); - } else { - subHandle = Meteor.subscribe.apply(Meteor, args); - } - - self.onViewDestroyed(function () { - subHandle.stop(); - }); - - return subHandle; -}; - -Blaze.View.prototype.firstNode = function () { - if (! this._isAttached) - throw new Error("View must be attached before accessing its DOM"); - - return this._domrange.firstNode(); -}; - -Blaze.View.prototype.lastNode = function () { - if (! this._isAttached) - throw new Error("View must be attached before accessing its DOM"); - - return this._domrange.lastNode(); -}; - -Blaze._fireCallbacks = function (view, which) { - Blaze._withCurrentView(view, function () { - Tracker.nonreactive(function fireCallbacks() { - var cbs = view._callbacks[which]; - for (var i = 0, N = (cbs && cbs.length); i < N; i++) - cbs[i] && cbs[i].call(view); - }); - }); -}; - -Blaze._createView = function (view, parentView, forExpansion) { - if (view.isCreated) - throw new Error("Can't render the same View twice"); - - view.parentView = (parentView || null); - view.isCreated = true; - if (forExpansion) - view._isCreatedForExpansion = true; - - Blaze._fireCallbacks(view, 'created'); -}; - -var doFirstRender = function (view, initialContent) { - var domrange = new Blaze._DOMRange(initialContent); - view._domrange = domrange; - domrange.view = view; - view.isRendered = true; - Blaze._fireCallbacks(view, 'rendered'); - - var teardownHook = null; - - domrange.onAttached(function attached(range, element) { - view._isAttached = true; - - teardownHook = Blaze._DOMBackend.Teardown.onElementTeardown( - element, function teardown() { - Blaze._destroyView(view, true /* _skipNodes */); - }); - }); - - // tear down the teardown hook - view.onViewDestroyed(function () { - teardownHook && teardownHook.stop(); - teardownHook = null; - }); - - return domrange; -}; - -// Take an uncreated View `view` and create and render it to DOM, -// setting up the autorun that updates the View. Returns a new -// DOMRange, which has been associated with the View. -// -// The private arguments `_workStack` and `_intoArray` are passed in -// by Blaze._materializeDOM and are only present for recursive calls -// (when there is some other _materializeView on the stack). If -// provided, then we avoid the mutual recursion of calling back into -// Blaze._materializeDOM so that deep View hierarchies don't blow the -// stack. Instead, we push tasks onto workStack for the initial -// rendering and subsequent setup of the View, and they are done after -// we return. When there is a _workStack, we do not return the new -// DOMRange, but instead push it into _intoArray from a _workStack -// task. -Blaze._materializeView = function (view, parentView, _workStack, _intoArray) { - Blaze._createView(view, parentView); - - var domrange; - var lastHtmljs; - // We don't expect to be called in a Computation, but just in case, - // wrap in Tracker.nonreactive. - Tracker.nonreactive(function () { - view.autorun(function doRender(c) { - // `view.autorun` sets the current view. - view.renderCount++; - view._isInRender = true; - // Any dependencies that should invalidate this Computation come - // from this line: - var htmljs = view._render(); - view._isInRender = false; - - if (! c.firstRun) { - Tracker.nonreactive(function doMaterialize() { - // re-render - var rangesAndNodes = Blaze._materializeDOM(htmljs, [], view); - if (! Blaze._isContentEqual(lastHtmljs, htmljs)) { - domrange.setMembers(rangesAndNodes); - Blaze._fireCallbacks(view, 'rendered'); - } - }); - } - lastHtmljs = htmljs; - - // Causes any nested views to stop immediately, not when we call - // `setMembers` the next time around the autorun. Otherwise, - // helpers in the DOM tree to be replaced might be scheduled - // to re-run before we have a chance to stop them. - Tracker.onInvalidate(function () { - if (domrange) { - domrange.destroyMembers(); - } - }); - }, undefined, 'materialize'); - - // first render. lastHtmljs is the first htmljs. - var initialContents; - if (! _workStack) { - initialContents = Blaze._materializeDOM(lastHtmljs, [], view); - domrange = doFirstRender(view, initialContents); - initialContents = null; // help GC because we close over this scope a lot - } else { - // We're being called from Blaze._materializeDOM, so to avoid - // recursion and save stack space, provide a description of the - // work to be done instead of doing it. Tasks pushed onto - // _workStack will be done in LIFO order after we return. - // The work will still be done within a Tracker.nonreactive, - // because it will be done by some call to Blaze._materializeDOM - // (which is always called in a Tracker.nonreactive). - initialContents = []; - // push this function first so that it happens last - _workStack.push(function () { - domrange = doFirstRender(view, initialContents); - initialContents = null; // help GC because of all the closures here - _intoArray.push(domrange); - }); - // now push the task that calculates initialContents - _workStack.push(_.bind(Blaze._materializeDOM, null, - lastHtmljs, initialContents, view, _workStack)); - } - }); - - if (! _workStack) { - return domrange; - } else { - return null; - } -}; - -// Expands a View to HTMLjs, calling `render` recursively on all -// Views and evaluating any dynamic attributes. Calls the `created` -// callback, but not the `materialized` or `rendered` callbacks. -// Destroys the view immediately, unless called in a Tracker Computation, -// in which case the view will be destroyed when the Computation is -// invalidated. If called in a Tracker Computation, the result is a -// reactive string; that is, the Computation will be invalidated -// if any changes are made to the view or subviews that might affect -// the HTML. -Blaze._expandView = function (view, parentView) { - Blaze._createView(view, parentView, true /*forExpansion*/); - - view._isInRender = true; - var htmljs = Blaze._withCurrentView(view, function () { - return view._render(); - }); - view._isInRender = false; - - var result = Blaze._expand(htmljs, view); - - if (Tracker.active) { - Tracker.onInvalidate(function () { - Blaze._destroyView(view); - }); - } else { - Blaze._destroyView(view); - } - - return result; -}; - -// Options: `parentView` -Blaze._HTMLJSExpander = HTML.TransformingVisitor.extend(); -Blaze._HTMLJSExpander.def({ - visitObject: function (x) { - if (x instanceof Blaze.Template) - x = x.constructView(); - if (x instanceof Blaze.View) - return Blaze._expandView(x, this.parentView); - - // this will throw an error; other objects are not allowed! - return HTML.TransformingVisitor.prototype.visitObject.call(this, x); - }, - visitAttributes: function (attrs) { - // expand dynamic attributes - if (typeof attrs === 'function') - attrs = Blaze._withCurrentView(this.parentView, attrs); - - // call super (e.g. for case where `attrs` is an array) - return HTML.TransformingVisitor.prototype.visitAttributes.call(this, attrs); - }, - visitAttribute: function (name, value, tag) { - // expand attribute values that are functions. Any attribute value - // that contains Views must be wrapped in a function. - if (typeof value === 'function') - value = Blaze._withCurrentView(this.parentView, value); - - return HTML.TransformingVisitor.prototype.visitAttribute.call( - this, name, value, tag); - } -}); - -// Return Blaze.currentView, but only if it is being rendered -// (i.e. we are in its render() method). -var currentViewIfRendering = function () { - var view = Blaze.currentView; - return (view && view._isInRender) ? view : null; -}; - -Blaze._expand = function (htmljs, parentView) { - parentView = parentView || currentViewIfRendering(); - return (new Blaze._HTMLJSExpander( - {parentView: parentView})).visit(htmljs); -}; - -Blaze._expandAttributes = function (attrs, parentView) { - parentView = parentView || currentViewIfRendering(); - return (new Blaze._HTMLJSExpander( - {parentView: parentView})).visitAttributes(attrs); -}; - -Blaze._destroyView = function (view, _skipNodes) { - if (view.isDestroyed) - return; - view.isDestroyed = true; - - Blaze._fireCallbacks(view, 'destroyed'); - - // Destroy views and elements recursively. If _skipNodes, - // only recurse up to views, not elements, for the case where - // the backend (jQuery) is recursing over the elements already. - - if (view._domrange) - view._domrange.destroyMembers(_skipNodes); -}; - -Blaze._destroyNode = function (node) { - if (node.nodeType === 1) - Blaze._DOMBackend.Teardown.tearDownElement(node); -}; - -// Are the HTMLjs entities `a` and `b` the same? We could be -// more elaborate here but the point is to catch the most basic -// cases. -Blaze._isContentEqual = function (a, b) { - if (a instanceof HTML.Raw) { - return (b instanceof HTML.Raw) && (a.value === b.value); - } else if (a == null) { - return (b == null); - } else { - return (a === b) && - ((typeof a === 'number') || (typeof a === 'boolean') || - (typeof a === 'string')); - } -}; - -/** - * @summary The View corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, `null`. - * @locus Client - * @type {Blaze.View} - */ -Blaze.currentView = null; - -Blaze._withCurrentView = function (view, func) { - var oldView = Blaze.currentView; - try { - Blaze.currentView = view; - return func(); - } finally { - Blaze.currentView = oldView; - } -}; - -// Blaze.render publicly takes a View or a Template. -// Privately, it takes any HTMLJS (extended with Views and Templates) -// except null or undefined, or a function that returns any extended -// HTMLJS. -var checkRenderContent = function (content) { - if (content === null) - throw new Error("Can't render null"); - if (typeof content === 'undefined') - throw new Error("Can't render undefined"); - - if ((content instanceof Blaze.View) || - (content instanceof Blaze.Template) || - (typeof content === 'function')) - return; - - try { - // Throw if content doesn't look like HTMLJS at the top level - // (i.e. verify that this is an HTML.Tag, or an array, - // or a primitive, etc.) - (new HTML.Visitor).visit(content); - } catch (e) { - // Make error message suitable for public API - throw new Error("Expected Template or View"); - } -}; - -// For Blaze.render and Blaze.toHTML, take content and -// wrap it in a View, unless it's a single View or -// Template already. -var contentAsView = function (content) { - checkRenderContent(content); - - if (content instanceof Blaze.Template) { - return content.constructView(); - } else if (content instanceof Blaze.View) { - return content; - } else { - var func = content; - if (typeof func !== 'function') { - func = function () { - return content; - }; - } - return Blaze.View('render', func); - } -}; - -// For Blaze.renderWithData and Blaze.toHTMLWithData, wrap content -// in a function, if necessary, so it can be a content arg to -// a Blaze.With. -var contentAsFunc = function (content) { - checkRenderContent(content); - - if (typeof content !== 'function') { - return function () { - return content; - }; - } else { - return content; - } -}; - -/** - * @summary Renders a template or View to DOM nodes and inserts it into the DOM, returning a rendered [View](#blaze_view) which can be passed to [`Blaze.remove`](#blaze_remove). - * @locus Client - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render. If a template, a View object is [constructed](#template_constructview). If a View, it must be an unrendered View, which becomes a rendered View and is returned. - * @param {DOMNode} parentNode The node that will be the parent of the rendered template. It must be an Element node. - * @param {DOMNode} [nextNode] Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode. - * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview). - */ -Blaze.render = function (content, parentElement, nextNode, parentView) { - if (! parentElement) { - Blaze._warn("Blaze.render without a parent element is deprecated. " + - "You must specify where to insert the rendered content."); - } - - if (nextNode instanceof Blaze.View) { - // handle omitted nextNode - parentView = nextNode; - nextNode = null; - } - - // parentElement must be a DOM node. in particular, can't be the - // result of a call to `$`. Can't check if `parentElement instanceof - // Node` since 'Node' is undefined in IE8. - if (parentElement && typeof parentElement.nodeType !== 'number') - throw new Error("'parentElement' must be a DOM node"); - if (nextNode && typeof nextNode.nodeType !== 'number') // 'nextNode' is optional - throw new Error("'nextNode' must be a DOM node"); - - parentView = parentView || currentViewIfRendering(); - - var view = contentAsView(content); - Blaze._materializeView(view, parentView); - - if (parentElement) { - view._domrange.attach(parentElement, nextNode); - } - - return view; -}; - -Blaze.insert = function (view, parentElement, nextNode) { - Blaze._warn("Blaze.insert has been deprecated. Specify where to insert the " + - "rendered content in the call to Blaze.render."); - - if (! (view && (view._domrange instanceof Blaze._DOMRange))) - throw new Error("Expected template rendered with Blaze.render"); - - view._domrange.attach(parentElement, nextNode); -}; - -/** - * @summary Renders a template or View to DOM nodes with a data context. Otherwise identical to `Blaze.render`. - * @locus Client - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render. - * @param {Object|Function} data The data context to use, or a function returning a data context. If a function is provided, it will be reactively re-run. - * @param {DOMNode} parentNode The node that will be the parent of the rendered template. It must be an Element node. - * @param {DOMNode} [nextNode] Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode. - * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview). - */ -Blaze.renderWithData = function (content, data, parentElement, nextNode, parentView) { - // We defer the handling of optional arguments to Blaze.render. At this point, - // `nextNode` may actually be `parentView`. - return Blaze.render(Blaze._TemplateWith(data, contentAsFunc(content)), - parentElement, nextNode, parentView); -}; - -/** - * @summary Removes a rendered View from the DOM, stopping all reactive updates and event listeners on it. Also destroys the Blaze.Template instance associated with the view. - * @locus Client - * @param {Blaze.View} renderedView The return value from `Blaze.render` or `Blaze.renderWithData`, or the `view` property of a Blaze.Template instance. Calling `Blaze.remove(Template.instance().view)` from within a template event handler will destroy the view as well as that template and trigger the template's `onDestroyed` handlers. - */ -Blaze.remove = function (view) { - if (! (view && (view._domrange instanceof Blaze._DOMRange))) - throw new Error("Expected template rendered with Blaze.render"); - - while (view) { - if (! view.isDestroyed) { - var range = view._domrange; - if (range.attached && ! range.parentRange) - range.detach(); - range.destroy(); - } - - view = view._hasGeneratedParent && view.parentView; - } -}; - -/** - * @summary Renders a template or View to a string of HTML. - * @locus Client - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML. - */ -Blaze.toHTML = function (content, parentView) { - parentView = parentView || currentViewIfRendering(); - - return HTML.toHTML(Blaze._expandView(contentAsView(content), parentView)); -}; - -/** - * @summary Renders a template or View to HTML with a data context. Otherwise identical to `Blaze.toHTML`. - * @locus Client - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML. - * @param {Object|Function} data The data context to use, or a function returning a data context. - */ -Blaze.toHTMLWithData = function (content, data, parentView) { - parentView = parentView || currentViewIfRendering(); - - return HTML.toHTML(Blaze._expandView(Blaze._TemplateWith( - data, contentAsFunc(content)), parentView)); -}; - -Blaze._toText = function (htmljs, parentView, textMode) { - if (typeof htmljs === 'function') - throw new Error("Blaze._toText doesn't take a function, just HTMLjs"); - - if ((parentView != null) && ! (parentView instanceof Blaze.View)) { - // omitted parentView argument - textMode = parentView; - parentView = null; - } - parentView = parentView || currentViewIfRendering(); - - if (! textMode) - throw new Error("textMode required"); - if (! (textMode === HTML.TEXTMODE.STRING || - textMode === HTML.TEXTMODE.RCDATA || - textMode === HTML.TEXTMODE.ATTRIBUTE)) - throw new Error("Unknown textMode: " + textMode); - - return HTML.toText(Blaze._expand(htmljs, parentView), textMode); -}; - -/** - * @summary Returns the current data context, or the data context that was used when rendering a particular DOM element or View from a Meteor template. - * @locus Client - * @param {DOMElement|Blaze.View} [elementOrView] Optional. An element that was rendered by a Meteor, or a View. - */ -Blaze.getData = function (elementOrView) { - var theWith; - - if (! elementOrView) { - theWith = Blaze.getView('with'); - } else if (elementOrView instanceof Blaze.View) { - var view = elementOrView; - theWith = (view.name === 'with' ? view : - Blaze.getView(view, 'with')); - } else if (typeof elementOrView.nodeType === 'number') { - if (elementOrView.nodeType !== 1) - throw new Error("Expected DOM element"); - theWith = Blaze.getView(elementOrView, 'with'); - } else { - throw new Error("Expected DOM element or View"); - } - - return theWith ? theWith.dataVar.get() : null; -}; - -// For back-compat -Blaze.getElementData = function (element) { - Blaze._warn("Blaze.getElementData has been deprecated. Use " + - "Blaze.getData(element) instead."); - - if (element.nodeType !== 1) - throw new Error("Expected DOM element"); - - return Blaze.getData(element); -}; - -// Both arguments are optional. - -/** - * @summary Gets either the current View, or the View enclosing the given DOM element. - * @locus Client - * @param {DOMElement} [element] Optional. If specified, the View enclosing `element` is returned. - */ -Blaze.getView = function (elementOrView, _viewName) { - var viewName = _viewName; - - if ((typeof elementOrView) === 'string') { - // omitted elementOrView; viewName present - viewName = elementOrView; - elementOrView = null; - } - - // We could eventually shorten the code by folding the logic - // from the other methods into this method. - if (! elementOrView) { - return Blaze._getCurrentView(viewName); - } else if (elementOrView instanceof Blaze.View) { - return Blaze._getParentView(elementOrView, viewName); - } else if (typeof elementOrView.nodeType === 'number') { - return Blaze._getElementView(elementOrView, viewName); - } else { - throw new Error("Expected DOM element or View"); - } -}; - -// Gets the current view or its nearest ancestor of name -// `name`. -Blaze._getCurrentView = function (name) { - var view = Blaze.currentView; - // Better to fail in cases where it doesn't make sense - // to use Blaze._getCurrentView(). There will be a current - // view anywhere it does. You can check Blaze.currentView - // if you want to know whether there is one or not. - if (! view) - throw new Error("There is no current view"); - - if (name) { - while (view && view.name !== name) - view = view.parentView; - return view || null; - } else { - // Blaze._getCurrentView() with no arguments just returns - // Blaze.currentView. - return view; - } -}; - -Blaze._getParentView = function (view, name) { - var v = view.parentView; - - if (name) { - while (v && v.name !== name) - v = v.parentView; - } - - return v || null; -}; - -Blaze._getElementView = function (elem, name) { - var range = Blaze._DOMRange.forElement(elem); - var view = null; - while (range && ! view) { - view = (range.view || null); - if (! view) { - if (range.parentRange) - range = range.parentRange; - else - range = Blaze._DOMRange.forElement(range.parentElement); - } - } - - if (name) { - while (view && view.name !== name) - view = view.parentView; - return view || null; - } else { - return view; - } -}; - -Blaze._addEventMap = function (view, eventMap, thisInHandler) { - thisInHandler = (thisInHandler || null); - var handles = []; - - if (! view._domrange) - throw new Error("View must have a DOMRange"); - - view._domrange.onAttached(function attached_eventMaps(range, element) { - _.each(eventMap, function (handler, spec) { - var clauses = spec.split(/,\s+/); - // iterate over clauses of spec, e.g. ['click .foo', 'click .bar'] - _.each(clauses, function (clause) { - var parts = clause.split(/\s+/); - if (parts.length === 0) - return; - - var newEvents = parts.shift(); - var selector = parts.join(' '); - handles.push(Blaze._EventSupport.listen( - element, newEvents, selector, - function (evt) { - if (! range.containsElement(evt.currentTarget)) - return null; - var handlerThis = thisInHandler || this; - var handlerArgs = arguments; - return Blaze._withCurrentView(view, function () { - return handler.apply(handlerThis, handlerArgs); - }); - }, - range, function (r) { - return r.parentRange; - })); - }); - }); - }); - - view.onViewDestroyed(function () { - _.each(handles, function (h) { - h.stop(); - }); - handles.length = 0; - }); -}; diff --git a/packages/blaze/view_tests.js b/packages/blaze/view_tests.js deleted file mode 100644 index c9f271723d..0000000000 --- a/packages/blaze/view_tests.js +++ /dev/null @@ -1,59 +0,0 @@ -if (Meteor.isClient) { - - Tinytest.add("blaze - view - callbacks", function (test) { - var R = ReactiveVar('foo'); - - var buf = ''; - - var v = Blaze.View(function () { - return R.get(); - }); - - v.onViewCreated(function () { - buf += 'c' + v.renderCount; - }); - v._onViewRendered(function () { - buf += 'r' + v.renderCount; - }); - v.onViewReady(function () { - buf += 'y' + v.renderCount; - }); - v.onViewDestroyed(function () { - buf += 'd' + v.renderCount; - }); - - test.equal(buf, ''); - - var div = document.createElement("DIV"); - test.isFalse(v.isRendered); - test.isFalse(v._isAttached); - test.equal(canonicalizeHtml(div.innerHTML), ""); - test.throws(function () { v.firstNode(); }, /View must be attached/); - test.throws(function () { v.lastNode(); }, /View must be attached/); - Blaze.render(v, div); - test.equal(buf, 'c0r1'); - test.equal(typeof (v.firstNode().nodeType), "number"); - test.equal(typeof (v.lastNode().nodeType), "number"); - test.isTrue(v.isRendered); - test.isTrue(v._isAttached); - test.equal(buf, 'c0r1'); - test.equal(canonicalizeHtml(div.innerHTML), "foo"); - Tracker.flush(); - test.equal(buf, 'c0r1y1'); - - R.set("bar"); - Tracker.flush(); - test.equal(buf, 'c0r1y1r2y2'); - test.equal(canonicalizeHtml(div.innerHTML), "bar"); - - Blaze.remove(v); - test.equal(buf, 'c0r1y1r2y2d2'); - test.equal(canonicalizeHtml(div.innerHTML), ""); - - buf = ""; - R.set("baz"); - Tracker.flush(); - test.equal(buf, ""); - }); - -} diff --git a/packages/caching-html-compiler/README.md b/packages/caching-html-compiler/README.md deleted file mode 100644 index d64298c59f..0000000000 --- a/packages/caching-html-compiler/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# caching-html-compiler - -Provides a pluggable class used to compile HTML-style templates in Meteor build plugins. This abstracts out a lot of the functionality you would need to implement the following plugins: - -1. `templating` -2. `static-html` -3. `simple:markdown-templating` - -It provides automatic caching and handles communicating with the build plugin APIs. The actual functions that convert HTML into compiled form are passed in as arguments into the constructor, allowing those functions to be unit tested separately from the caching and file system functionality. - -------- - -### new CachingHtmlCompiler(name, tagScannerFunc, tagHandlerFunc) - -Constructs a new CachingHtmlCompiler that can be passed into `Plugin.registerCompiler`. - -#### Arguments - -1. `name` The name of the compiler, used when printing errors. Should probably be the same as the name of the build plugin and package it is used in. -2. `tagScannerFunc` A function that takes a string representing a template file as input, and returns an array of Tag objects. See the README for `templating-tools` for more information about the Tag object. -3. `tagHandlerFunc` A function that takes an array of Tag objects (the output of the previous argument) and returns an object with `js`, `body`, `head`, and `bodyAttr` properties, which will be added to the app through the build plugin API. - -#### Example - -Here is some example code from the `templating` package: - -```js -Plugin.registerCompiler({ - extensions: ['html'], - archMatching: 'web', - isTemplate: true -}, () => new CachingHtmlCompiler( - "templating", - TemplatingTools.scanHtmlForTags, - TemplatingTools.compileTagsWithSpacebars -)); -``` diff --git a/packages/caching-html-compiler/caching-html-compiler.js b/packages/caching-html-compiler/caching-html-compiler.js deleted file mode 100644 index 43e01ee3ef..0000000000 --- a/packages/caching-html-compiler/caching-html-compiler.js +++ /dev/null @@ -1,141 +0,0 @@ -const path = Plugin.path; - -// The CompileResult type for this CachingCompiler is the return value of -// htmlScanner.scan: a {js, head, body, bodyAttrs} object. -CachingHtmlCompiler = class CachingHtmlCompiler extends CachingCompiler { - /** - * Constructor for CachingHtmlCompiler - * @param {String} name The name of the compiler, printed in errors - - * should probably always be the same as the name of the build - * plugin/package - * @param {Function} tagScannerFunc Transforms a template file (commonly - * .html) into an array of Tags - * @param {Function} tagHandlerFunc Transforms an array of tags into a - * results object with js, body, head, and bodyAttrs properties - */ - constructor(name, tagScannerFunc, tagHandlerFunc) { - super({ - compilerName: name, - defaultCacheSize: 1024*1024*10, - }); - - this._bodyAttrInfo = null; - - this.tagScannerFunc = tagScannerFunc; - this.tagHandlerFunc = tagHandlerFunc; - } - - // Implements method from CachingCompilerBase - compileResultSize(compileResult) { - function lengthOrZero(field) { - return field ? field.length : 0; - } - return lengthOrZero(compileResult.head) + lengthOrZero(compileResult.body) + - lengthOrZero(compileResult.js); - } - - // Overrides method from CachingCompiler - processFilesForTarget(inputFiles) { - this._bodyAttrInfo = {}; - super.processFilesForTarget(inputFiles); - } - - // Implements method from CachingCompilerBase - getCacheKey(inputFile) { - // Note: the path is only used for errors, so it doesn't have to be part - // of the cache key. - return inputFile.getSourceHash(); - } - - // Implements method from CachingCompiler - compileOneFile(inputFile) { - const contents = inputFile.getContentsAsString(); - const inputPath = inputFile.getPathInPackage(); - try { - const tags = this.tagScannerFunc({ - sourceName: inputPath, - contents: contents, - tagNames: ["body", "head", "template"] - }); - - return this.tagHandlerFunc(tags); - } catch (e) { - if (e instanceof TemplatingTools.CompileError) { - inputFile.error({ - message: e.message, - line: e.line - }); - return null; - } else { - throw e; - } - } - } - - // Implements method from CachingCompilerBase - addCompileResult(inputFile, compileResult) { - let allJavaScript = ""; - - if (compileResult.head) { - inputFile.addHtml({ section: "head", data: compileResult.head }); - } - - if (compileResult.body) { - inputFile.addHtml({ section: "body", data: compileResult.body }); - } - - if (compileResult.js) { - allJavaScript += compileResult.js; - } - - if (! _.isEmpty(compileResult.bodyAttrs)) { - Object.keys(compileResult.bodyAttrs).forEach((attr) => { - const value = compileResult.bodyAttrs[attr]; - if (this._bodyAttrInfo.hasOwnProperty(attr) && - this._bodyAttrInfo[attr].value !== value) { - // two conflicting attributes on tags in two different template - // files - inputFile.error({ - message: - ` declarations have conflicting values for the '${ attr }' ` + - `attribute in the following files: ` + - this._bodyAttrInfo[attr].inputFile.getPathInPackage() + - `, ${ inputFile.getPathInPackage() }` - }); - } else { - this._bodyAttrInfo[attr] = {inputFile, value}; - } - }); - - // Add JavaScript code to set attributes on body - allJavaScript += -`Meteor.startup(function() { - var attrs = ${JSON.stringify(compileResult.bodyAttrs)}; - for (var prop in attrs) { - document.body.setAttribute(prop, attrs[prop]); - } -}); -`; - } - - - if (allJavaScript) { - const filePath = inputFile.getPathInPackage(); - // XXX this path manipulation may be unnecessarily complex - let pathPart = path.dirname(filePath); - if (pathPart === '.') - pathPart = ''; - if (pathPart.length && pathPart !== path.sep) - pathPart = pathPart + path.sep; - const ext = path.extname(filePath); - const basename = path.basename(filePath, ext); - - // XXX generate a source map - - inputFile.addJavaScript({ - path: path.join(pathPart, "template." + basename + ".js"), - data: allJavaScript - }); - } - } -} diff --git a/packages/caching-html-compiler/package.js b/packages/caching-html-compiler/package.js deleted file mode 100644 index df7d81a1d1..0000000000 --- a/packages/caching-html-compiler/package.js +++ /dev/null @@ -1,21 +0,0 @@ -Package.describe({ - version: '1.0.6', - // Brief, one-line summary of the package. - summary: 'Pluggable class for compiling HTML into templates', - // By default, Meteor will default to using README.md for documentation. - // To avoid submitting documentation, set this field to null. - documentation: 'README.md' -}); - -Package.onUse(function(api) { - api.use([ - 'underscore', - 'caching-compiler', - 'templating-tools', - 'ecmascript' - ]); - - api.addFiles('caching-html-compiler.js', 'server'); - - api.export("CachingHtmlCompiler", 'server'); -}); diff --git a/packages/html-tools/.gitignore b/packages/html-tools/.gitignore deleted file mode 100644 index 677a6fc263..0000000000 --- a/packages/html-tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.build* diff --git a/packages/html-tools/README.md b/packages/html-tools/README.md deleted file mode 100644 index 5b60bae263..0000000000 --- a/packages/html-tools/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# html-tools - -A lightweight HTML tokenizer and parser which outputs to the HTMLjs -object representation. Special hooks allow the syntax to be extended -to parse an HTML-like template language like Spacebars. - -``` -HTMLTools.parseFragment("
Hello
World
") - -=> HTML.DIV({'class':'greeting'}, "Hello", HTML.BR(), "World")) -``` - -This package is used by the Spacebars compiler, which normally only -runs at bundle time but can also be used at runtime on the client or -server. - -## Invoking the Parser - -`HTMLTools.parseFragment(input, options)` - Takes an input string or Scanner object and returns HTMLjs. - -In the basic case, where no options are passed, `parseFragment` will consume the entire input (the full string or the rest of the Scanner). - -The options are as follows: - -#### getTemplateTag - -This option extends the HTML parser to parse template tags such as `{{foo}}`. - -`getTemplateTag: function (scanner, templateTagPosition) { ... }` - A function for the parser to call after every HTML token and at various positions within tags. If the function returns an instanceof `HTMLTools.TemplateTag`, it is inserted into the HTMLjs tree at the appropriate location. The constructor is `HTMLTools.TemplateTag(props)`, where props is an object whose properties are copied to the `TemplateTag` instance. You can also call the constructor with no arguments and assign whatever properties you want, or you can subclass `TemplateTag`. - -There are four possible outcomes when `getTemplateTag` is called: - -* Not a template tag - Leave the scanner as is, and return `null`. A quick peek at the next character should bail to this case if the start of a template tag is not seen. -* Bad template tag - Call `scanner.fatal`, which aborts parsing completely. Once the beginning of a template tag is seen, `getTemplateTag` will generally want to commit, and either succeed or fail trying). -* Good template tag - Advance the scanner to the end of the template tag and return an `HTMLTools.TemplateTag` object. -* Comment tag - Advance the scanner and return `null`. For example, a Spacebars comment is `{{! foo}}`. - -The `templateTagPosition` argument to `getTemplateTag` is one of: - -* `HTMLTools.TEMPLATE_TAG_POSITION.ELEMENT` - At "element level," meaning somewhere an HTML tag could be. -* `HTMLTools.TEMPLATE_TAG_POSITION.IN_START_TAG` - Inside a start tag, as in `
`, where you might otherwise find `name=value`. -* `HTMLTools.TEMPLATE_TAG_POSITION.IN_ATTRIBUTE` - Inside the value of an HTML attribute, as in `
`. -* `HTMLTools.TEMPLATE_TAG_POSITION.IN_RCDATA` - Inside a TEXTAREA or a block helper inside an attribute, where character references are allowed ("replaced character data") but not tags. -* `HTMLTools.TEMPLATE_TAG_POSITION.IN_RAWTEXT` - In a context where character references are not parsed, such as a script tag, style tag, or markdown helper. - -It's completely normal for `getTemplateTag` to invoke `HTMLTools.parseFragment` recursively on the same scanner (see `shouldStop`). If it does so, the same value of `getTemplateTag` must be passed to the second invocation. - -At the moment, template tags must begin with `{`. The parser does not try calling `getTemplateTag` for every character of an HTML document, only at token boundaries, and it knows to always end a token at `{`. - -#### textMode - -The `textMode` option, if present, causes the parser to parse text (such as the contents of a `', TEXTAREA({value: "asdf"})); - succeed('', TEXTAREA({x: "y", value: "asdf"})); - succeed('', TEXTAREA({value: "

"})); - succeed('', - TEXTAREA({value: ["a", CharRef({html: '&', str: '&'}), "b"]})); - succeed('', TEXTAREA({value: "\n', TEXTAREA()); - succeed('', TEXTAREA({value: "asdf"})); - succeed('', TEXTAREA({value: "\nasdf"})); - succeed('', TEXTAREA({value: "\n"})); - succeed('', TEXTAREA({value: "asdf\n"})); - succeed('', TEXTAREA({value: ""})); - succeed('', TEXTAREA({value: "asdf"})); - fatal(''); - succeed('', TEXTAREA({value: "&"})); - succeed('asdf', - [TEXTAREA({value: "x

', [DIV("x"), TEXTAREA()]); - - // CR/LF behavior - succeed('', BR({x:''})); - succeed('', BR({x:''})); - succeed('
', BR({x:'y'})); - succeed('
', BR({x:'y'})); - succeed('
', BR({x:'y'})); - succeed('
', BR({x:'y'})); - succeed('
', BR({x:'y'})); - succeed('', Comment('\n')); - succeed('', Comment('\n')); - succeed('', TEXTAREA({value: 'a\nb\nc'})); - succeed('', TEXTAREA({value: 'a\nb\nc'})); - succeed('
', BR({x:'\n\n'})); - succeed('
', BR({x:'\n\n'})); - succeed('
', BR({x:'y'})); - fatal('
'); - - succeed('',SCRIPT('var x="
";')); - succeed('',SCRIPT('var x=1 && 0;')); - - succeed('', SCRIPT("asdf")); - succeed('', SCRIPT({x: "y"}, "asdf")); - succeed('', SCRIPT("

")); - succeed('', SCRIPT("a&b")); - succeed('', SCRIPT("\n', SCRIPT("\n")); - succeed('', SCRIPT("")); - succeed('', SCRIPT("asdf")); - fatal('', SCRIPT("&davidgreenspan;")); - succeed('', SCRIPT("&")); - succeed('asdf', - [SCRIPT("asdf', STYLE("asdf")); - succeed('', STYLE({x: "y"}, "asdf")); - succeed('', STYLE("

")); - succeed('', STYLE("a&b")); - succeed('', STYLE("\n', STYLE("\n")); - succeed('', STYLE("")); - succeed('', STYLE("asdf")); - fatal('', STYLE("&davidgreenspan;")); - succeed('', STYLE("&")); - succeed('asdf', - [STYLE("

Hello

")), - BlazeTools.toJS(DIV(P({id:'foo'}, 'Hello')))); - - _.each(['asdf
', '{{!foo}}
', '{{!foo}}
', - 'asdf', '{{!foo}}', '{{!foo}} '], function (badFrag) { - test.throws(function() { - HTMLTools.parseFragment(badFrag); - }, /Unexpected HTML close tag/); - }); - - (function () { - var p = HTMLTools.parseFragment('

'); - test.equal(p.tagName, 'p'); - test.equal(p.attrs, null); - test.isTrue(p instanceof HTML.Tag); - test.equal(p.children.length, 0); - })(); - - (function () { - var p = HTMLTools.parseFragment('

x

'); - test.equal(p.tagName, 'p'); - test.equal(p.attrs, null); - test.isTrue(p instanceof HTML.Tag); - test.equal(p.children.length, 1); - test.equal(p.children[0], 'x'); - })(); - - (function () { - var p = HTMLTools.parseFragment('

xA

'); - test.equal(p.tagName, 'p'); - test.equal(p.attrs, null); - test.isTrue(p instanceof HTML.Tag); - test.equal(p.children.length, 2); - test.equal(p.children[0], 'x'); - - test.isTrue(p.children[1] instanceof HTML.CharRef); - test.equal(p.children[1].html, 'A'); - test.equal(p.children[1].str, 'A'); - })(); - - (function () { - var pp = HTMLTools.parseFragment('

x

y

'); - test.isTrue(pp instanceof Array); - test.equal(pp.length, 2); - - test.equal(pp[0].tagName, 'p'); - test.equal(pp[0].attrs, null); - test.isTrue(pp[0] instanceof HTML.Tag); - test.equal(pp[0].children.length, 1); - test.equal(pp[0].children[0], 'x'); - - test.equal(pp[1].tagName, 'p'); - test.equal(pp[1].attrs, null); - test.isTrue(pp[1] instanceof HTML.Tag); - test.equal(pp[1].children.length, 1); - test.equal(pp[1].children[0], 'y'); - })(); - - var scanner = new Scanner('asdf'); - scanner.pos = 1; - test.equal(HTMLTools.parseFragment(scanner), 'sdf'); - - test.throws(function () { - var scanner = new Scanner('asdf

'); - scanner.pos = 1; - HTMLTools.parseFragment(scanner); - }); -}); - -Tinytest.add("html-tools - getTemplateTag", function (test) { - - // match a simple tag consisting of `{{`, an optional `!`, one - // or more ASCII letters, spaces or html tags, and a closing `}}`. - var mustache = /^\{\{(!?[a-zA-Z 0-9]+)\}\}/; - - // This implementation of `getTemplateTag` looks for "{{" and if it - // finds it, it will match the regex above or fail fatally trying. - // The object it returns is opaque to the tokenizer/parser and can - // be anything we want. - var getTemplateTag = function (scanner, position) { - if (! (scanner.peek() === '{' && // one-char peek is just an optimization - scanner.rest().slice(0, 2) === '{{')) - return null; - - var match = mustache.exec(scanner.rest()); - if (! match) - scanner.fatal("Bad mustache"); - - scanner.pos += match[0].length; - - if (match[1].charAt(0) === '!') - return null; // `{{!foo}}` is like a comment - - return TemplateTag({ stuff: match[1] }); - }; - - - - var succeed = function (input, expected) { - var endPos = input.indexOf('^^^'); - if (endPos < 0) - endPos = input.length; - - var scanner = new Scanner(input.replace('^^^', '')); - scanner.getTemplateTag = getTemplateTag; - var result; - try { - result = getContent(scanner); - } catch (e) { - result = String(e); - } - test.equal(scanner.pos, endPos); - test.equal(BlazeTools.toJS(result), BlazeTools.toJS(expected)); - }; - - var fatal = function (input, messageContains) { - var scanner = new Scanner(input); - scanner.getTemplateTag = getTemplateTag; - var error; - try { - getContent(scanner); - } catch (e) { - error = e; - } - test.isTrue(error); - if (messageContains) - test.isTrue(messageContains && error.message.indexOf(messageContains) >= 0, error.message); - }; - - - succeed('{{foo}}', TemplateTag({stuff: 'foo'})); - - succeed('{{foo}}', - A({href: "http://www.apple.com/"}, TemplateTag({stuff: 'foo'}))); - - // tags not parsed in comments - succeed('', Comment("{{foo}}")); - succeed('', Comment("{{foo")); - - succeed('&am{{foo}}p;', ['&am', TemplateTag({stuff: 'foo'}), 'p;']); - - // can't start a mustache and not finish it - fatal('{{foo'); - fatal('{{'); - - // no mustache allowed in tag name - fatal('<{{a}}>'); - fatal('<{{a}}b>'); - fatal(''); - - // single curly brace is no biggie - succeed('a{b', 'a{b'); - succeed('
', BR({x:'{'})); - succeed('
', BR({x:'{foo}'})); - - succeed('
', BR(Attrs(TemplateTag({stuff: 'x'})))); - succeed('
', BR(Attrs(TemplateTag({stuff: 'x'}), - TemplateTag({stuff: 'y'})))); - succeed('
', BR(Attrs({y: ''}, TemplateTag({stuff: 'x'})))); - fatal('
'); - fatal('
'); - succeed('
', BR({x: TemplateTag({stuff: 'y'}), z: ''})); - succeed('
', BR({x: ['y', TemplateTag({stuff: 'z'}), 'w']})); - succeed('
', BR({x: ['y', TemplateTag({stuff: 'z'}), 'w']})); - succeed('
', BR({x: ['y ', TemplateTag({stuff: 'z'}), - TemplateTag({stuff: 'w'}), ' v']})); - // Slash is parsed as part of unquoted attribute! This is consistent with - // the HTML tokenization spec. It seems odd for some inputs but is probably - // for cases like `` or ``. - succeed('
', BR({x: [TemplateTag({stuff: 'y'}), '/']})); - succeed('
', BR({x: [TemplateTag({stuff: 'z'}), - TemplateTag({stuff: 'w'})]})); - fatal('
'); - - succeed('
', BR({x:CharRef({html: '&', str: '&'})})); - - - // check tokenization of stache tags with spaces - succeed('
', BR(Attrs(TemplateTag({stuff: 'x 1'})))); - succeed('
', BR(Attrs(TemplateTag({stuff: 'x 1'}), - TemplateTag({stuff: 'y 2'})))); - succeed('
', BR(Attrs({y:''}, TemplateTag({stuff: 'x 1'})))); - fatal('
'); - fatal('
'); - succeed('
', BR({x: TemplateTag({stuff: 'y 2'}), z: ''})); - succeed('
', BR({x: ['y', TemplateTag({stuff: 'z 3'}), 'w']})); - succeed('
', BR({x: ['y', TemplateTag({stuff: 'z 3'}), 'w']})); - succeed('
', BR({x: ['y ', TemplateTag({stuff: 'z 3'}), - TemplateTag({stuff: 'w 4'}), ' v']})); - succeed('
', BR({x: [TemplateTag({stuff: 'y 2'}), '/']})); - succeed('
', BR({x: [TemplateTag({stuff: 'z 3'}), - TemplateTag({stuff: 'w 4'})]})); - - succeed('

', P()); - - succeed('x{{foo}}{{bar}}y', ['x', TemplateTag({stuff: 'foo'}), - TemplateTag({stuff: 'bar'}), 'y']); - succeed('x{{!foo}}{{!bar}}y', 'xy'); - succeed('x{{!foo}}{{bar}}y', ['x', TemplateTag({stuff: 'bar'}), 'y']); - succeed('x{{foo}}{{!bar}}y', ['x', TemplateTag({stuff: 'foo'}), 'y']); - succeed('
{{!foo}}{{!bar}}
', DIV()); - succeed('
{{!foo}}
{{!bar}}
', DIV(BR())); - succeed('
{{!foo}} {{!bar}}
', DIV(" ")); - succeed('
{{!foo}}
{{!bar}}
', DIV(" ", BR(), " ")); - succeed('{{!
}}', null); - succeed('{{!
}}', null); - - succeed('', null); - succeed('{{!foo}}', null); - - succeed('', - TEXTAREA(Attrs({x:"1"}, TemplateTag({stuff: 'a'}), - TemplateTag({stuff: 'b'})))); - -}); diff --git a/packages/html-tools/scanner.js b/packages/html-tools/scanner.js deleted file mode 100644 index d110a8a814..0000000000 --- a/packages/html-tools/scanner.js +++ /dev/null @@ -1,82 +0,0 @@ -// This is a Scanner class suitable for any parser/lexer/tokenizer. -// -// A Scanner has an immutable source document (string) `input` and a current -// position `pos`, an index into the string, which can be set at will. -// -// * `new Scanner(input)` - constructs a Scanner with source string `input` -// * `scanner.rest()` - returns the rest of the input after `pos` -// * `scanner.peek()` - returns the character at `pos` -// * `scanner.isEOF()` - true if `pos` is at or beyond the end of `input` -// * `scanner.fatal(msg)` - throw an error indicating a problem at `pos` - -Scanner = HTMLTools.Scanner = function (input) { - this.input = input; // public, read-only - this.pos = 0; // public, read-write -}; - -Scanner.prototype.rest = function () { - // Slicing a string is O(1) in modern JavaScript VMs (including old IE). - return this.input.slice(this.pos); -}; - -Scanner.prototype.isEOF = function () { - return this.pos >= this.input.length; -}; - -Scanner.prototype.fatal = function (msg) { - // despite this default, you should always provide a message! - msg = (msg || "Parse error"); - - var CONTEXT_AMOUNT = 20; - - var input = this.input; - var pos = this.pos; - var pastInput = input.substring(pos - CONTEXT_AMOUNT - 1, pos); - if (pastInput.length > CONTEXT_AMOUNT) - pastInput = '...' + pastInput.substring(-CONTEXT_AMOUNT); - - var upcomingInput = input.substring(pos, pos + CONTEXT_AMOUNT + 1); - if (upcomingInput.length > CONTEXT_AMOUNT) - upcomingInput = upcomingInput.substring(0, CONTEXT_AMOUNT) + '...'; - - var positionDisplay = ((pastInput + upcomingInput).replace(/\n/g, ' ') + '\n' + - (new Array(pastInput.length + 1).join(' ')) + "^"); - - var e = new Error(msg + "\n" + positionDisplay); - - e.offset = pos; - var allPastInput = input.substring(0, pos); - e.line = (1 + (allPastInput.match(/\n/g) || []).length); - e.col = (1 + pos - allPastInput.lastIndexOf('\n')); - e.scanner = this; - - throw e; -}; - -// Peek at the next character. -// -// If `isEOF`, returns an empty string. -Scanner.prototype.peek = function () { - return this.input.charAt(this.pos); -}; - -// Constructs a `getFoo` function where `foo` is specified with a regex. -// The regex should start with `^`. The constructed function will return -// match group 1, if it exists and matches a non-empty string, or else -// the entire matched string (or null if there is no match). -// -// A `getFoo` function tries to match and consume a foo. If it succeeds, -// the current position of the scanner is advanced. If it fails, the -// current position is not advanced and a falsy value (typically null) -// is returned. -makeRegexMatcher = function (regex) { - return function (scanner) { - var match = regex.exec(scanner.rest()); - - if (! match) - return null; - - scanner.pos += match[0].length; - return match[1] || match[0]; - }; -}; diff --git a/packages/html-tools/templatetag.js b/packages/html-tools/templatetag.js deleted file mode 100644 index f94f9fd214..0000000000 --- a/packages/html-tools/templatetag.js +++ /dev/null @@ -1,29 +0,0 @@ -// _assign is like _.extend or the upcoming Object.assign. -// Copy src's own, enumerable properties onto tgt and return -// tgt. -var _hasOwnProperty = Object.prototype.hasOwnProperty; -var _assign = function (tgt, src) { - for (var k in src) { - if (_hasOwnProperty.call(src, k)) - tgt[k] = src[k]; - } - return tgt; -}; - - -HTMLTools.TemplateTag = function (props) { - if (! (this instanceof HTMLTools.TemplateTag)) - // called without `new` - return new HTMLTools.TemplateTag; - - if (props) - _assign(this, props); -}; - -_assign(HTMLTools.TemplateTag.prototype, { - constructorName: 'HTMLTools.TemplateTag', - toJS: function (visitor) { - return visitor.generateCall(this.constructorName, - _assign({}, this)); - } -}); diff --git a/packages/html-tools/tokenize.js b/packages/html-tools/tokenize.js deleted file mode 100644 index de0b9c0662..0000000000 --- a/packages/html-tools/tokenize.js +++ /dev/null @@ -1,513 +0,0 @@ -// Token types: -// -// { t: 'Doctype', -// v: String (entire Doctype declaration from the source), -// name: String, -// systemId: String (optional), -// publicId: String (optional) -// } -// -// { t: 'Comment', -// v: String (not including "") -// } -// -// { t: 'Chars', -// v: String (pure text like you might pass to document.createTextNode, -// no character references) -// } -// -// { t: 'Tag', -// isEnd: Boolean (optional), -// isSelfClosing: Boolean (optional), -// n: String (tag name, in lowercase or camel case), -// attrs: dictionary of { String: [tokens] } -// OR [{ String: [tokens] }, TemplateTag tokens...] -// (only for start tags; required) -// } -// -// { t: 'CharRef', -// v: String (entire character reference from the source, e.g. "&"), -// cp: [Integer] (array of Unicode code point numbers it expands to) -// } -// -// We keep around both the original form of the character reference and its -// expansion so that subsequent processing steps have the option to -// re-emit it (if they are generating HTML) or interpret it. Named and -// numerical code points may be more than 16 bits, in which case they -// need to passed through codePointToString to make a JavaScript string. -// Most named entities and all numeric character references are one codepoint -// (e.g. "&" is [38]), but a few are two codepoints. -// -// { t: 'TemplateTag', -// v: HTMLTools.TemplateTag -// } - -// The HTML tokenization spec says to preprocess the input stream to replace -// CR(LF)? with LF. However, preprocessing `scanner` would complicate things -// by making indexes not match the input (e.g. for error messages), so we just -// keep in mind as we go along that an LF might be represented by CRLF or CR. -// In most cases, it doesn't actually matter what combination of whitespace -// characters are present (e.g. inside tags). -var HTML_SPACE = /^[\f\n\r\t ]/; - -var convertCRLF = function (str) { - return str.replace(/\r\n?/g, '\n'); -}; - -getComment = HTMLTools.Parse.getComment = function (scanner) { - if (scanner.rest().slice(0, 4) !== ''); - if (closePos < 0) - scanner.fatal("Unclosed HTML comment"); - - var commentContents = rest.slice(0, closePos); - if (commentContents.slice(-1) === '-') - scanner.fatal("HTML comment must end at first `--`"); - if (commentContents.indexOf("--") >= 0) - scanner.fatal("HTML comment cannot contain `--` anywhere"); - if (commentContents.indexOf('\u0000') >= 0) - scanner.fatal("HTML comment cannot contain NULL"); - - scanner.pos += closePos + 3; - - return { t: 'Comment', - v: convertCRLF(commentContents) }; -}; - -var skipSpaces = function (scanner) { - while (HTML_SPACE.test(scanner.peek())) - scanner.pos++; -}; - -var requireSpaces = function (scanner) { - if (! HTML_SPACE.test(scanner.peek())) - scanner.fatal("Expected space"); - skipSpaces(scanner); -}; - -var getDoctypeQuotedString = function (scanner) { - var quote = scanner.peek(); - if (! (quote === '"' || quote === "'")) - scanner.fatal("Expected single or double quote in DOCTYPE"); - scanner.pos++; - - if (scanner.peek() === quote) - // prevent a falsy return value (empty string) - scanner.fatal("Malformed DOCTYPE"); - - var str = ''; - var ch; - while ((ch = scanner.peek()), ch !== quote) { - if ((! ch) || (ch === '\u0000') || (ch === '>')) - scanner.fatal("Malformed DOCTYPE"); - str += ch; - scanner.pos++; - } - - scanner.pos++; - - return str; -}; - -// See http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#the-doctype. -// -// If `getDocType` sees "') || (ch === '\u0000')) - scanner.fatal('Malformed DOCTYPE'); - var name = ch; - scanner.pos++; - - while ((ch = scanner.peek()), ! (HTML_SPACE.test(ch) || ch === '>')) { - if ((! ch) || (ch === '\u0000')) - scanner.fatal('Malformed DOCTYPE'); - name += ch; - scanner.pos++; - } - name = HTMLTools.asciiLowerCase(name); - - // Now we're looking at a space or a `>`. - skipSpaces(scanner); - - var systemId = null; - var publicId = null; - - if (scanner.peek() !== '>') { - // Now we're essentially in the "After DOCTYPE name state" of the tokenizer, - // but we're not looking at space or `>`. - - // this should be "public" or "system". - var publicOrSystem = HTMLTools.asciiLowerCase(scanner.rest().slice(0, 6)); - - if (publicOrSystem === 'system') { - scanner.pos += 6; - requireSpaces(scanner); - systemId = getDoctypeQuotedString(scanner); - skipSpaces(scanner); - if (scanner.peek() !== '>') - scanner.fatal("Malformed DOCTYPE"); - } else if (publicOrSystem === 'public') { - scanner.pos += 6; - requireSpaces(scanner); - publicId = getDoctypeQuotedString(scanner); - if (scanner.peek() !== '>') { - requireSpaces(scanner); - if (scanner.peek() !== '>') { - systemId = getDoctypeQuotedString(scanner); - skipSpaces(scanner); - if (scanner.peek() !== '>') - scanner.fatal("Malformed DOCTYPE"); - } - } - } else { - scanner.fatal("Expected PUBLIC or SYSTEM in DOCTYPE"); - } - } - - // looking at `>` - scanner.pos++; - var result = { t: 'Doctype', - v: scanner.input.slice(start, scanner.pos), - name: name }; - - if (systemId) - result.systemId = systemId; - if (publicId) - result.publicId = publicId; - - return result; -}; - -// The special character `{` is only allowed as the first character -// of a Chars, so that we have a chance to detect template tags. -var getChars = makeRegexMatcher(/^[^&<\u0000][^&<\u0000{]*/); - -var assertIsTemplateTag = function (x) { - if (! (x instanceof HTMLTools.TemplateTag)) - throw new Error("Expected an instance of HTMLTools.TemplateTag"); - return x; -}; - -// Returns the next HTML token, or `null` if we reach EOF. -// -// Note that if we have a `getTemplateTag` function that sometimes -// consumes characters and emits nothing (e.g. in the case of template -// comments), we may go from not-at-EOF to at-EOF and return `null`, -// while otherwise we always find some token to return. -getHTMLToken = HTMLTools.Parse.getHTMLToken = function (scanner, dataMode) { - var result = null; - if (scanner.getTemplateTag) { - // Try to parse a template tag by calling out to the provided - // `getTemplateTag` function. If the function returns `null` but - // consumes characters, it must have parsed a comment or something, - // so we loop and try it again. If it ever returns `null` without - // consuming anything, that means it didn't see anything interesting - // so we look for a normal token. If it returns a truthy value, - // the value must be instanceof HTMLTools.TemplateTag. We wrap it - // in a Special token. - var lastPos = scanner.pos; - result = scanner.getTemplateTag( - scanner, - (dataMode === 'rcdata' ? TEMPLATE_TAG_POSITION.IN_RCDATA : - (dataMode === 'rawtext' ? TEMPLATE_TAG_POSITION.IN_RAWTEXT : - TEMPLATE_TAG_POSITION.ELEMENT))); - - if (result) - return { t: 'TemplateTag', v: assertIsTemplateTag(result) }; - else if (scanner.pos > lastPos) - return null; - } - - var chars = getChars(scanner); - if (chars) - return { t: 'Chars', - v: convertCRLF(chars) }; - - var ch = scanner.peek(); - if (! ch) - return null; // EOF - - if (ch === '\u0000') - scanner.fatal("Illegal NULL character"); - - if (ch === '&') { - if (dataMode !== 'rawtext') { - var charRef = getCharacterReference(scanner); - if (charRef) - return charRef; - } - - scanner.pos++; - return { t: 'Chars', - v: '&' }; - } - - // If we're here, we're looking at `<`. - - if (scanner.peek() === '<' && dataMode) { - // don't interpret tags - scanner.pos++; - return { t: 'Chars', - v: '<' }; - } - - // `getTag` will claim anything starting with `<` not followed by `!`. - // `getComment` takes `")), - { t: 'Comment', v: ' hello ' }); - - ignore(""); - ignore("', 'Unclosed'); - fatal('', 'cannot contain'); - fatal('', 'must end at first'); - - fatal('', 'cannot contain'); - fatal('', 'cannot contain'); - - succeed('', ''); - succeed('', '-x'); - succeed('', 'x'); - succeed('', ' hello - - world '); -}); - -Tinytest.add("html-tools - doctype", function (test) { - var succeed = function (input, expectedProps) { - var scanner = new Scanner(input); - var result = getDoctype(scanner); - test.isTrue(result); - test.equal(scanner.pos, result.v.length); - test.equal(input.slice(0, result.v.length), result.v); - var actualProps = _.extend({}, result); - delete actualProps.t; - delete actualProps.v; - test.equal(actualProps, expectedProps); - }; - - var fatal = function (input, messageContains) { - var scanner = new Scanner(input); - var error; - try { - getDoctype(scanner); - } catch (e) { - error = e; - } - test.isTrue(error); - if (messageContains) - test.isTrue(error.message.indexOf(messageContains) >= 0, error.message); - }; - - test.equal(getDoctype(new Scanner("x")), - { t: 'Doctype', - v: '', - name: 'html' }); - - test.equal(getDoctype(new Scanner("x")), - { t: 'Doctype', - v: "", - name: 'html', - systemId: 'about:legacy-compat' }); - - test.equal(getDoctype(new Scanner("x")), - { t: 'Doctype', - v: "", - name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN' }); - - test.equal(getDoctype(new Scanner("x")), - { t: 'Doctype', - v: "", - name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN', - systemId: 'http://www.w3.org/TR/html4/strict.dtd' }); - - succeed('', {name: 'html'}); - succeed('', {name: 'html'}); - succeed('', {name: 'html'}); - succeed('', {name: 'html'}); - succeed('', {name: 'html'}); - succeed('', {name: 'html'}); - fatal('', 'Expected space'); - fatal('', 'Malformed DOCTYPE'); - fatal('', 'Malformed DOCTYPE'); - fatal('', {name: 'html', systemId: 'about:legacy-compat'}); - succeed('', {name: 'html', systemId: 'about:legacy-compat'}); - succeed("", {name: 'html', systemId: 'about:legacy-compat'}); - succeed("", {name: 'html', systemId: 'about:legacy-compat'}); - succeed('', {name: 'html', systemId: 'about:legacy-compat'}); - fatal('', 'Expected PUBLIC or SYSTEM'); - fatal('', 'Expected space'); - fatal(''); - fatal(''); - fatal('">'); - fatal(''); - fatal(''); - fatal(''); - fatal(''); - fatal(''); - - succeed('', - { name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN'}); - succeed('', - { name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN'}); - succeed('', - { name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN', - systemId: 'http://www.w3.org/TR/REC-html40/strict.dtd'}); - succeed('', - { name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN', - systemId: 'http://www.w3.org/TR/REC-html40/strict.dtd'}); - succeed('', - { name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN', - systemId: 'http://www.w3.org/TR/REC-html40/strict.dtd'}); - succeed('', - { name: 'html', - publicId: '-//W3C//DTD HTML 4.0//EN', - systemId: 'http://www.w3.org/TR/REC-html40/strict.dtd'}); - fatal(''); - fatal(''); -}); - -Tinytest.add("html-tools - tokenize", function (test) { - - var fatal = function (input, messageContains) { - var error; - try { - tokenize(input); - } catch (e) { - error = e; - } - test.isTrue(error); - if (messageContains) - test.isTrue(error.message.indexOf(messageContains) >= 0, error.message); - }; - - - test.equal(tokenize(''), []); - test.equal(tokenize('abc'), [{t: 'Chars', v: 'abc'}]); - test.equal(tokenize('&'), [{t: 'Chars', v: '&'}]); - test.equal(tokenize('&'), [{t: 'CharRef', v: '&', cp: [38]}]); - test.equal(tokenize('ok fine'), - [{t: 'Chars', v: 'ok'}, - {t: 'CharRef', v: ' ', cp: [32]}, - {t: 'Chars', v: 'fine'}]); - - test.equal(tokenize('ac'), - [{t: 'Chars', - v: 'a'}, - {t: 'Comment', - v: 'b'}, - {t: 'Chars', - v: 'c'}]); - - test.equal(tokenize('
'), [{t: 'Tag', n: 'a'}]); - - fatal('<'); - fatal(''), - [{t: 'Tag', n: 'a', - attrs: { b: [{t: 'Chars', v: 'c'}], - d: [{t: 'Chars', v: 'e'}], - f: [{t: 'Chars', v: 'g'}], - h: [] }}]); - - fatal(''); - fatal(''); - fatal(''); - - test.equal(tokenize(''), [{t: 'Tag', n: 'a', isSelfClosing: true}]); - - fatal(''); - fatal(''); - fatal(''); - fatal(''); - - test.equal(tokenize(''), - [{t: 'Tag', n: 'a#', - attrs: { b0: [{t: 'Chars', v: 'c@'}], - d1: [{t: 'Chars', v: 'e2'}], - 'f#': [{t: 'Chars', v: 'g '}], - h: [] }}]); - - test.equal(tokenize('
'), - [{t: 'Tag', n: 'div', attrs: { 'class': [] }}, - {t: 'Tag', n: 'div', isEnd: true}]); - - test.equal(tokenize('
'), - [{t: 'Tag', n: 'div', attrs: { 'class': [{t: 'Chars', v: '&'}] }}]); - test.equal(tokenize('
'), - [{t: 'Tag', n: 'div', attrs: { 'class': [{t: 'Chars', v: '&'}] }}]); - test.equal(tokenize('
'), - [{t: 'Tag', n: 'div', attrs: { 'class': [{t: 'CharRef', v: '&', cp: [38]}] }}]); - - test.equal(tokenize('
'), - [{t: 'Tag', n: 'div', attrs: { 'class': [ - {t: 'Chars', v: 'aa&'}, - {t: 'CharRef', v: '𝕫', cp: [120171]}, - {t: 'CharRef', v: '∾̳', cp: [8766, 819]}, - {t: 'Chars', v: '&bb'} - ] }}]); - - test.equal(tokenize('
'), - [{t: 'Tag', n: 'div', attrs: { 'class': [ - {t: 'Chars', v: 'aa &'}, - {t: 'CharRef', v: '𝕫', cp: [120171]}, - {t: 'CharRef', v: '∾̳', cp: [8766, 819]}, - {t: 'Chars', v: '& bb'} - ] }}]); - - test.equal(tokenize(''), - [{t: 'Tag', n: 'a', attrs: { b: [{t: 'Chars', v: '\'`<>&'}] }}]); - test.equal(tokenize('&\'>'), - [{t: 'Tag', n: 'a', attrs: { b: [{t: 'Chars', v: '"`<>&'}] }}]); - - fatal('>'); - fatal('>c'); - test.equal(tokenize(''), - [{t: 'Tag', n: 'a', attrs: { b: [{t: 'Chars', v: '>c' }] }}]); - test.equal(tokenize(''), - [{t: 'Tag', n: 'a', attrs: { b: [{t: 'Chars', v: '>c' }] }}]); - fatal(''); - fatal(''); - fatal(''); - - fatal(''); - - fatal(''); - fatal('<{{a}}>'); - fatal(''); // end tag can't have attributes - fatal(''); // end tag can't be self-closing - fatal(''); -}); diff --git a/packages/html-tools/utils.js b/packages/html-tools/utils.js deleted file mode 100644 index 934bc09e02..0000000000 --- a/packages/html-tools/utils.js +++ /dev/null @@ -1,50 +0,0 @@ - -HTMLTools = {}; -HTMLTools.Parse = {}; - -var asciiLowerCase = HTMLTools.asciiLowerCase = function (str) { - return str.replace(/[A-Z]/g, function (c) { - return String.fromCharCode(c.charCodeAt(0) + 32); - }); -}; - -var svgCamelCaseAttributes = 'attributeName attributeType baseFrequency baseProfile calcMode clipPathUnits contentScriptType contentStyleType diffuseConstant edgeMode externalResourcesRequired filterRes filterUnits glyphRef glyphRef gradientTransform gradientTransform gradientUnits gradientUnits kernelMatrix kernelUnitLength kernelUnitLength kernelUnitLength keyPoints keySplines keyTimes lengthAdjust limitingConeAngle markerHeight markerUnits markerWidth maskContentUnits maskUnits numOctaves pathLength patternContentUnits patternTransform patternUnits pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits refX refY repeatCount repeatDur requiredExtensions requiredFeatures specularConstant specularExponent specularExponent spreadMethod spreadMethod startOffset stdDeviation stitchTiles surfaceScale surfaceScale systemLanguage tableValues targetX targetY textLength textLength viewBox viewTarget xChannelSelector yChannelSelector zoomAndPan'.split(' '); - -var properAttributeCaseMap = (function (map) { - for (var i = 0; i < svgCamelCaseAttributes.length; i++) { - var a = svgCamelCaseAttributes[i]; - map[asciiLowerCase(a)] = a; - } - return map; -})({}); - -var properTagCaseMap = (function (map) { - var knownElements = HTML.knownElementNames; - for (var i = 0; i < knownElements.length; i++) { - var a = knownElements[i]; - map[asciiLowerCase(a)] = a; - } - return map; -})({}); - -// Take a tag name in any case and make it the proper case for HTML. -// -// Modern browsers let you embed SVG in HTML, but SVG elements are special -// in that they have a case-sensitive DOM API (nodeName, getAttribute, -// setAttribute). For example, it has to be `setAttribute("viewBox")`, -// not `"viewbox"`. However, the browser's HTML parser is NOT case sensitive -// and will fix the case for you, so if you write `` -// you actually get a `"viewBox"` attribute. Any HTML-parsing toolchain -// must do the same. -HTMLTools.properCaseTagName = function (name) { - var lowered = asciiLowerCase(name); - return properTagCaseMap.hasOwnProperty(lowered) ? - properTagCaseMap[lowered] : lowered; -}; - -// See docs for properCaseTagName. -HTMLTools.properCaseAttributeName = function (name) { - var lowered = asciiLowerCase(name); - return properAttributeCaseMap.hasOwnProperty(lowered) ? - properAttributeCaseMap[lowered] : lowered; -}; diff --git a/packages/htmljs/.gitignore b/packages/htmljs/.gitignore deleted file mode 100644 index 677a6fc263..0000000000 --- a/packages/htmljs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.build* diff --git a/packages/htmljs/README.md b/packages/htmljs/README.md deleted file mode 100644 index d2b06c4b00..0000000000 --- a/packages/htmljs/README.md +++ /dev/null @@ -1,427 +0,0 @@ -# HTMLjs - -HTMLjs is a small library for expressing HTML trees with a concise -syntax. It is used to render content in Blaze and to represent -templates during compilation. - -``` -var UL = HTML.UL, LI = HTML.LI, B = HTML.B; - -HTML.toHTML( - UL({id: 'mylist'}, - LI({'class': 'item'}, "Hello ", B("world"), "!"), - LI({'class': 'item'}, "Goodbye, world"))) -``` - -``` -
    -
  • Hello world!
  • -
  • Goodbye, world
  • -
-``` - -The functions `UL`, `LI`, and `B` are constructors which -return instances of `HTML.Tag`. These tag objects can -then be converted to an HTML string or directly into DOM nodes. - -The flexible structure of HTMLjs allows different kinds of Blaze -directives to be embedded in the tree. HTMLjs does not know about -these directives, which are considered "foreign objects." - -# Built-in Types - -The following types are built into HTMLjs. Built-in methods like -`HTML.toHTML` require a tree consisting only of these types. - -* __`null`, `undefined`__ - Render to nothing. - -* __boolean, number__ - Render to the string form of the boolean or number. - -* __string__ - Renders to a text node (or part of an attribute value). All characters are safe, and no HTML injection is possible. The string `""` renders `<a>` in HTML, and `document.createTextNode("")` in DOM. - -* __Array__ - Renders to its elements in order. An array may be empty. Arrays are detected using `HTML.isArray(...)`. - -* __`HTML.Tag`__ - Renders to an HTML element (including start tag, contents, and end tag). - -* __`HTML.CharRef({html: ..., str: ...})`__ - Renders to a character reference (such as ` `) when generating HTML. - -* __`HTML.Comment(text)`__ - Renders to an HTML comment. - -* __`HTML.Raw(html)`__ - Renders to a string of HTML to include verbatim. - -The `new` keyword is not required before constructors of HTML object types. - -All objects and arrays should be considered immutable. Instance properties -are public, but they should only be read, not written. Arrays should not -be spliced in place. This convention allows for clean patterns of -processing and transforming HTMLjs trees. - - -## HTML.Tag - -An `HTML.Tag` is created using a tag-specific constructor, like -`HTML.P` for a `

` tag or `HTML.INPUT` for an `` tag. The -resulting object is `instanceof HTML.Tag`. (The `HTML.Tag` -constructor should not be called directly.) - -Tag constructors take an optional attributes dictionary followed -by zero or more children: - -``` -HTML.HR() - -HTML.DIV(HTML.P("First paragraph"), - HTML.P("Second paragraph")) - -HTML.INPUT({type: "text"}) - -HTML.SPAN({'class': "foo"}, "Some text") -``` - -### Instance properties - -Tags have the following properties: - -* `tagName` - The tag name in lowercase (or camelCase) -* `children` - An array of children (always present) -* `attrs` - An attributes dictionary, `null`, or an array (see below) - - -### Special forms of attributes - -The attributes of a Tag may be an array of dictionaries. In order -for a tag constructor to recognize an array as the attributes argument, -it must be written as `HTML.Attrs(attrs1, attrs2, ...)`, as in this -example: - -``` -var extraAttrs = {'class': "container"}; - -var div = HTML.DIV(HTML.Attrs({id: "main"}, extraAttrs), - "This is the content."); - -div.attrs // => [{id: "main"}, {'class': "container"}] -``` - -`HTML.Attrs` may also be used to pass a foreign object in place of -an attributes dictionary of a tag. - - - -### Normalized Case for Tag Names - -The `tagName` field is always in "normalized case," which is the -official case for that particular element name (usually lowercase). -For example, `HTML.DIV().tagName` is `"div"`. For some elements -used in inline SVG graphics, the correct case is "camelCase." For -example, there is an element named `clipPath`. - -Web browsers have a confusing policy about case. They perform case -normalization when parsing HTML, but not when creating SVG elements -at runtime; the correct case is required. - -Therefore, in order to avoid ever having to normalize case at -runtime, the policy of HTMLjs is to put the burden on the caller -of functions like `HTML.ensureTag` -- for example, a template -engine -- of supplying correct normalized case. - -Briefly put, normlized case is usually lowercase, except for certain -elements where it is camelCase. - - -### Known Elements - -HTMLjs comes preloaded with constructors for all "known" HTML and -SVG elements. You can use `HTML.P`, `HTML.DIV`, and so on out of -the box. If you want to create a tag like `` for some reason, -you have to tell HTMLjs to create the `HTML.FOO` constructor for you -using `HTML.ensureTag` or `HTML.getTag`. - -HTMLjs's lists of known elements are public because they are useful to -other packages that provide additional functions not found here, like -functions for normalizing case. - - - -## Foreign objects - -Arbitrary objects are allowed in HTMLjs trees, which is useful for -adapting HTMLjs to a wide variety of uses. Such objects are called -foreign objects. - -The one restriction on foreign objects is that they must be -instances of a class -- so-called "constructed objects" (see -`HTML.isConstructedObject`) -- so that they can be distinguished -from the vanilla JS objects that represent attributes dictionaries -when constructing Tags. - -Functions are also considered foreign objects. - -## HTML.getTag(tagName) - -* `tagName` - A string in normalized case - -Creates a tag constructor for `tagName`, assigns it to the `HTML` -namespace object, and returns it. - -For example, `HTML.getTag("p")` returns `HTML.P`. `HTML.getTag("foo")` -will create and return `HTML.FOO`. - -It's very important that `tagName` be in normalized case, or else -an incorrect tag constructor will be registered and used henceforth. - - -## HTML.ensureTag(tagName) - -* `tagName` - A string in normalized case - -Ensures that a tag constructor (like `HTML.FOO`) exists for a tag -name (like `"foo"`), creating it if necessary. Like `HTML.getTag` -but does not return the tag constructor. - - -## HTML.isTagEnsured(tagName) - -* `tagName` - A string in normalized case - -Returns whether a particular tag is guaranteed to be available on -the `HTML` object (under the name returned by `HTML.getSymbolName`). - -Useful for code generators. - - -## HTML.getSymbolName(tagName) - -* `tagName` - A string in normalized case - -Returns the name of the all-caps constructor (like `"FOO"`) for a -tag name in normalized case (like `"foo"`). - -In addition to converting `tagName` to all-caps, hyphens (`-`) in -tag names are converted to underscores (`_`). - -Useful for code generators. - - -## HTML.knownElementNames - -An array of all known HTML5 and SVG element names in normalized case. - - -## HTML.knownSVGElementNames - -An array of all known SVG element names in normalized case. - -The `"a"` element is not included because it is primarily a non-SVG -element. - - -## HTML.voidElementNames - -An array of all "void" element names in normalized case. Void -elements are elements with a start tag and no end tag, such as BR, -HR, IMG, and INPUT. - -The HTML spec defines a closed class of void elements. - - -## HTML.isKnownElement(tagName) - -* `tagName` - A string in normalized case - -Returns whether `tagName` is a known HTML5 or SVG element. - - -## HTML.isKnownSVGElement(tagName) - -* `tagName` - A string in normalized case - -Returns whether `tagName` is the name of a known SVG element. - - -## HTML.isVoidElement(tagName) - -* `tagName` - A string in normalized case - -Returns whether `tagName` is the name of a void element. - - -## HTML.CharRef({html: ..., str: ...}) - -Represents a character reference like ` `. - -A CharRef is not required for escaping special characters like `<`, -which are automatically escaped by HTMLjs. For example, -`HTML.toHTML("<")` is `"<"`. Also, now that browsers speak -Unicode, non-ASCII characters typically do not need to be expressed -as character references either. The purpose of `CharRef` is offer -control over the generated HTML, allowing template engines to -preserve any character references that they come across. - -Constructing a CharRef requires two strings, the uninterpreted -"HTML" form and the interpreted "string" form. Both are required -to be present, and it is up to the caller to make sure the -information is accurate. - -Examples of valid CharRefs: - -* `HTML.CharRef({html: '&', str: '&'})` -* `HTML.CharRef({html: ' ', str: '\u00A0'}) - -Instance properties: `.html`, `.str` - - -## HTML.Comment(value) - -* `value` - String - -Represents an HTML Comment. For example, `HTML.Comment("foo")` represents -the comment ``. - -The value string should not contain two consecutive hyphens (`--`) or start -or end with a hyphen. If it does, the offending hyphens will be stripped -before generating HTML. - -Instance properties: `value` - - -## HTML.Raw(value) - -* `value` - String - -Represents HTML code to be inserted verbatim. `value` must consist -of a valid, complete fragment of HTML, with all tags closed and -all required end tags present. - -No security checks are performed, and no special characters are -escaped. `Raw` should not be used if there are other ways of -accomplishing the same result. HTML supplied by an application -user should not be rendered unless the user is trusted, and even -then, there could be strange results if required end tags are -missing. - -Instance properties: `value` - - -## HTML.isArray(x) - -Returns whether `x` is considered an array for the purposes of -HTMLjs. An array is an object created using `[...]` or -`new Array`. - -This function is provided because there are several common ways to -determine whether an object should be treated as an array in -JavaScript. - - -## HTML.isConstructedObject(x) - -Returns whether `x` is a "constructed object," which is (loosely -speaking) an object that was created with `new Foo` (for some `Foo`) -rather than with `{...}` (a vanilla object). Vanilla objects are used -as attribute dictionaries when constructing tags, while constructed -objects are used as children. - -For example, in `HTML.DIV({id:"foo"})`, `{id:"foo"}` is a vanilla -object. In `HTML.DIV(HTML.SPAN("text"))`, the `HTML.SPAN` is a -constructed object. - -A simple constructed object can be created as follows: - -``` -var Foo = function () {}; -var x = new Foo; // x is a constructed object -``` - -In particular, the test is that `x` is an object and `x.constructor` -is set, but on a prototype of the object, not the object itself. -The above example works because JavaScript sets -`Foo.prototype.constructor = Foo` when you create a function `Foo`. - - -## HTML.isNully(content) - -Returns true if `content` is `null`, `undefined`, an empty array, -or an array of only "nully" elements. - - -## HTML.isValidAttributeName(name) - -Returns whether `name` is a valid name for an attribute of an HTML tag -or element. `name` must: - -* Start with `:`, `_`, `A-Z` or `a-z` -* Consist only of those characters plus `-`, `.`, and `0-9`. - -Discussion: The HTML spec and the DOM API (`setAttribute`) have different -definitions of what characters are legal in an attribute. The HTML -parser is extremely permissive (allowing, for example, ``), while -`setAttribute` seems to use something like the XML grammar for names (and -throws an error if a name is invalid, making that attribute unsettable). -If we knew exactly what grammar browsers used for `setAttribute`, we could -include various Unicode ranges in what's legal. For now, we allow ASCII chars -that are known to be valid XML, valid HTML, and settable via `setAttribute`. - -See and -. - - -## HTML.flattenAttributes(attrs) - -If `attrs` is an array, the attribute dictionaries in the array are -combined into a single attributes dictionary, which is returned. -Any "nully" attribute values (see `HTML.isNully`) are ignored in -the process. If `attrs` is a single attribute dictionary, a copy -is returned with any nully attributes removed. If `attrs` is -equal to null or an empty array, `null` is returned. - -Attribute dictionaries are combined by assigning the name/value -pairs in array order, with later values overwriting previous -values. - -`attrs` must not contain any foreign objects. - - -## HTML.toHTML(content) - -* `content` - any HTMLjs content - -Returns a string of HTML generated from `content`. - -For example: - -``` -HTML.toHTML(HTML.HR()) // => "


" -``` - -Foreign objects are not allowed in `content`. To generate HTML -containing foreign objects, create a subclass of -`HTML.ToHTMLVisitor` and override `visitObject`. - - -## HTML.toText(content, textMode) - -* `content` - any HTMLjs content -* `textMode` - the type of text to generate; one of - `HTML.TEXTMODE.STRING`, `HTML.TEXTMODE.RCDATA`, or - `HTML.TEXTMODE.ATTRIBUTE` - -Generating HTML or DOM from HTMLjs content requires generating text -for attribute values and for the contents of TEXTAREA elements, -among others. The input content may contain strings, arrays, -booleans, numbers, nulls, and CharRefs. Behavior on other types -is undefined. - -The required `textMode` argument specifies the type of text to -generate: - -* `HTML.TEXTMODE.STRING` - a string with no special - escaping or encoding performed, suitable for passing to - `setAttribute` or `document.createTextNode`. -* `HTML.TEXTMODE.RCDATA` - a string with `<` and `&` encoded - as character references (and CharRefs included in their - "HTML" form), suitable for including in a string of HTML -* `HTML.TEXTMODE.ATTRIBUTE` - a string with `"` and `&` encoded - as character references (and CharRefs included in their - "HTML" form), suitable for including in an HTML attribute - value surrounded by double quotes diff --git a/packages/htmljs/html.js b/packages/htmljs/html.js deleted file mode 100644 index ce758772dc..0000000000 --- a/packages/htmljs/html.js +++ /dev/null @@ -1,268 +0,0 @@ - - -HTML.Tag = function () {}; -HTML.Tag.prototype.tagName = ''; // this will be set per Tag subclass -HTML.Tag.prototype.attrs = null; -HTML.Tag.prototype.children = Object.freeze ? Object.freeze([]) : []; -HTML.Tag.prototype.htmljsType = HTML.Tag.htmljsType = ['Tag']; - -// Given "p" create the function `HTML.P`. -var makeTagConstructor = function (tagName) { - // HTMLTag is the per-tagName constructor of a HTML.Tag subclass - var HTMLTag = function (/*arguments*/) { - // Work with or without `new`. If not called with `new`, - // perform instantiation by recursively calling this constructor. - // We can't pass varargs, so pass no args. - var instance = (this instanceof HTML.Tag) ? this : new HTMLTag; - - var i = 0; - var attrs = arguments.length && arguments[0]; - if (attrs && (typeof attrs === 'object')) { - // Treat vanilla JS object as an attributes dictionary. - if (! HTML.isConstructedObject(attrs)) { - instance.attrs = attrs; - i++; - } else if (attrs instanceof HTML.Attrs) { - var array = attrs.value; - if (array.length === 1) { - instance.attrs = array[0]; - } else if (array.length > 1) { - instance.attrs = array; - } - i++; - } - } - - - // If no children, don't create an array at all, use the prototype's - // (frozen, empty) array. This way we don't create an empty array - // every time someone creates a tag without `new` and this constructor - // calls itself with no arguments (above). - if (i < arguments.length) - instance.children = SLICE.call(arguments, i); - - return instance; - }; - HTMLTag.prototype = new HTML.Tag; - HTMLTag.prototype.constructor = HTMLTag; - HTMLTag.prototype.tagName = tagName; - - return HTMLTag; -}; - -// Not an HTMLjs node, but a wrapper to pass multiple attrs dictionaries -// to a tag (for the purpose of implementing dynamic attributes). -var Attrs = HTML.Attrs = function (/*attrs dictionaries*/) { - // Work with or without `new`. If not called with `new`, - // perform instantiation by recursively calling this constructor. - // We can't pass varargs, so pass no args. - var instance = (this instanceof Attrs) ? this : new Attrs; - - instance.value = SLICE.call(arguments); - - return instance; -}; - -////////////////////////////// KNOWN ELEMENTS - -HTML.getTag = function (tagName) { - var symbolName = HTML.getSymbolName(tagName); - if (symbolName === tagName) // all-caps tagName - throw new Error("Use the lowercase or camelCase form of '" + tagName + "' here"); - - if (! HTML[symbolName]) - HTML[symbolName] = makeTagConstructor(tagName); - - return HTML[symbolName]; -}; - -HTML.ensureTag = function (tagName) { - HTML.getTag(tagName); // don't return it -}; - -HTML.isTagEnsured = function (tagName) { - return HTML.isKnownElement(tagName); -}; - -HTML.getSymbolName = function (tagName) { - // "foo-bar" -> "FOO_BAR" - return tagName.toUpperCase().replace(/-/g, '_'); -}; - -HTML.knownElementNames = 'a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption center cite code col colgroup command data datagrid datalist dd del details dfn dir div dl dt em embed eventsource fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins isindex kbd keygen label legend li link main map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr'.split(' '); -// (we add the SVG ones below) - -HTML.knownSVGElementNames = 'altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform circle clipPath color-profile cursor defs desc ellipse feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter font font-face font-face-format font-face-name font-face-src font-face-uri foreignObject g glyph glyphRef hkern image line linearGradient marker mask metadata missing-glyph path pattern polygon polyline radialGradient rect set stop style svg switch symbol text textPath title tref tspan use view vkern'.split(' '); -// Append SVG element names to list of known element names -HTML.knownElementNames = HTML.knownElementNames.concat(HTML.knownSVGElementNames); - -HTML.voidElementNames = 'area base br col command embed hr img input keygen link meta param source track wbr'.split(' '); - -// Speed up search through lists of known elements by creating internal "sets" -// of strings. -var YES = {yes:true}; -var makeSet = function (array) { - var set = {}; - for (var i = 0; i < array.length; i++) - set[array[i]] = YES; - return set; -}; -var voidElementSet = makeSet(HTML.voidElementNames); -var knownElementSet = makeSet(HTML.knownElementNames); -var knownSVGElementSet = makeSet(HTML.knownSVGElementNames); - -HTML.isKnownElement = function (tagName) { - return knownElementSet[tagName] === YES; -}; - -HTML.isKnownSVGElement = function (tagName) { - return knownSVGElementSet[tagName] === YES; -}; - -HTML.isVoidElement = function (tagName) { - return voidElementSet[tagName] === YES; -}; - - -// Ensure tags for all known elements -for (var i = 0; i < HTML.knownElementNames.length; i++) - HTML.ensureTag(HTML.knownElementNames[i]); - - -var CharRef = HTML.CharRef = function (attrs) { - if (! (this instanceof CharRef)) - // called without `new` - return new CharRef(attrs); - - if (! (attrs && attrs.html && attrs.str)) - throw new Error( - "HTML.CharRef must be constructed with ({html:..., str:...})"); - - this.html = attrs.html; - this.str = attrs.str; -}; -CharRef.prototype.htmljsType = CharRef.htmljsType = ['CharRef']; - -var Comment = HTML.Comment = function (value) { - if (! (this instanceof Comment)) - // called without `new` - return new Comment(value); - - if (typeof value !== 'string') - throw new Error('HTML.Comment must be constructed with a string'); - - this.value = value; - // Kill illegal hyphens in comment value (no way to escape them in HTML) - this.sanitizedValue = value.replace(/^-|--+|-$/g, ''); -}; -Comment.prototype.htmljsType = Comment.htmljsType = ['Comment']; - -var Raw = HTML.Raw = function (value) { - if (! (this instanceof Raw)) - // called without `new` - return new Raw(value); - - if (typeof value !== 'string') - throw new Error('HTML.Raw must be constructed with a string'); - - this.value = value; -}; -Raw.prototype.htmljsType = Raw.htmljsType = ['Raw']; - - -HTML.isArray = function (x) { - // could change this to use the more convoluted Object.prototype.toString - // approach that works when objects are passed between frames, but does - // it matter? - return (x instanceof Array); -}; - -HTML.isConstructedObject = function (x) { - // Figure out if `x` is "an instance of some class" or just a plain - // object literal. It correctly treats an object literal like - // `{ constructor: ... }` as an object literal. It won't detect - // instances of classes that lack a `constructor` property (e.g. - // if you assign to a prototype when setting up the class as in: - // `Foo = function () { ... }; Foo.prototype = { ... }`, then - // `(new Foo).constructor` is `Object`, not `Foo`). - return (x && (typeof x === 'object') && - (x.constructor !== Object) && - (typeof x.constructor === 'function') && - (x instanceof x.constructor)); -}; - -HTML.isNully = function (node) { - if (node == null) - // null or undefined - return true; - - if (HTML.isArray(node)) { - // is it an empty array or an array of all nully items? - for (var i = 0; i < node.length; i++) - if (! HTML.isNully(node[i])) - return false; - return true; - } - - return false; -}; - -HTML.isValidAttributeName = function (name) { - return /^[:_A-Za-z][:_A-Za-z0-9.\-]*/.test(name); -}; - -// If `attrs` is an array of attributes dictionaries, combines them -// into one. Removes attributes that are "nully." -HTML.flattenAttributes = function (attrs) { - if (! attrs) - return attrs; - - var isArray = HTML.isArray(attrs); - if (isArray && attrs.length === 0) - return null; - - var result = {}; - for (var i = 0, N = (isArray ? attrs.length : 1); i < N; i++) { - var oneAttrs = (isArray ? attrs[i] : attrs); - if ((typeof oneAttrs !== 'object') || - HTML.isConstructedObject(oneAttrs)) - throw new Error("Expected plain JS object as attrs, found: " + oneAttrs); - for (var name in oneAttrs) { - if (! HTML.isValidAttributeName(name)) - throw new Error("Illegal HTML attribute name: " + name); - var value = oneAttrs[name]; - if (! HTML.isNully(value)) - result[name] = value; - } - } - - return result; -}; - - - -////////////////////////////// TOHTML - -HTML.toHTML = function (content) { - return (new HTML.ToHTMLVisitor).visit(content); -}; - -// Escaping modes for outputting text when generating HTML. -HTML.TEXTMODE = { - STRING: 1, - RCDATA: 2, - ATTRIBUTE: 3 -}; - - -HTML.toText = function (content, textMode) { - if (! textMode) - throw new Error("textMode required for HTML.toText"); - if (! (textMode === HTML.TEXTMODE.STRING || - textMode === HTML.TEXTMODE.RCDATA || - textMode === HTML.TEXTMODE.ATTRIBUTE)) - throw new Error("Unknown textMode: " + textMode); - - var visitor = new HTML.ToTextVisitor({textMode: textMode});; - return visitor.visit(content); -}; diff --git a/packages/htmljs/htmljs_test.js b/packages/htmljs/htmljs_test.js deleted file mode 100644 index c0ef819fa8..0000000000 --- a/packages/htmljs/htmljs_test.js +++ /dev/null @@ -1,87 +0,0 @@ - -Tinytest.add("htmljs - getTag", function (test) { - var FOO = HTML.getTag('foo'); - test.isTrue(HTML.FOO === FOO); - var x = FOO(); - - test.equal(x.tagName, 'foo'); - test.isTrue(x instanceof HTML.FOO); - test.isTrue(x instanceof HTML.Tag); - test.equal(x.children, []); - test.equal(x.attrs, null); - - test.isTrue((new FOO) instanceof HTML.FOO); - test.isTrue((new FOO) instanceof HTML.Tag); - test.isFalse((new HTML.P) instanceof HTML.FOO); - - var result = HTML.ensureTag('Bar'); - test.equal(typeof result, 'undefined'); - var BAR = HTML.BAR; - test.equal(BAR().tagName, 'Bar'); -}); - -Tinytest.add("htmljs - construction", function (test) { - var A = HTML.getTag('a'); - var B = HTML.getTag('b'); - var C = HTML.getTag('c'); - - var a = A(0, B({q:0}, C(A(B({})), 'foo'))); - test.equal(a.tagName, 'a'); - test.equal(a.attrs, null); - test.equal(a.children.length, 2); - test.equal(a.children[0], 0); - var b = a.children[1]; - test.equal(b.tagName, 'b'); - test.equal(b.attrs, {q:0}); - test.equal(b.children.length, 1); - var c = b.children[0]; - test.equal(c.tagName, 'c'); - test.equal(c.attrs, null); - test.equal(c.children.length, 2); - test.equal(c.children[0].tagName, 'a'); - test.equal(c.children[0].attrs, null); - test.equal(c.children[0].children.length, 1); - test.equal(c.children[0].children[0].tagName, 'b'); - test.equal(c.children[0].children[0].children.length, 0); - test.equal(c.children[0].children[0].attrs, {}); - test.equal(c.children[1], 'foo'); - - var a2 = new A({m:1}, {n:2}, B(), {o:3}, 'foo'); - test.equal(a2.tagName, 'a'); - test.equal(a2.attrs, {m:1}); - test.equal(a2.children.length, 4); - test.equal(a2.children[0], {n:2}); - test.equal(a2.children[1].tagName, 'b'); - test.equal(a2.children[2], {o:3}); - test.equal(a2.children[3], 'foo'); - - // tests of HTML.isConstructedObject (indirectly) - test.equal(A({x:1}).children.length, 0); - var f = function () {}; - test.equal(A(new f).children.length, 1); - test.equal(A(new Date).children.length, 1); - test.equal(A({constructor: 'blah'}).children.length, 0); - test.equal(A({constructor: Object}).children.length, 0); - - test.equal(HTML.toHTML(HTML.CharRef({html: '&', str: '&'})), '&'); - test.throws(function () { - HTML.CharRef({html: '&'}); // no 'str' - }); -}); - -Tinytest.add("htmljs - utils", function (test) { - - test.notEqual("\u00c9".toLowerCase(), "\u00c9"); - test.equal(HTMLTools.asciiLowerCase("\u00c9"), "\u00c9"); - - test.equal(HTMLTools.asciiLowerCase("Hello There"), "hello there"); - - test.isTrue(HTML.isVoidElement("br")); - test.isFalse(HTML.isVoidElement("div")); - test.isTrue(HTML.isKnownElement("div")); - -}); - -Tinytest.add("htmljs - details", function (test) { - test.equal(HTML.toHTML(false), "false"); -}); diff --git a/packages/htmljs/package.js b/packages/htmljs/package.js deleted file mode 100644 index 4e04ef077d..0000000000 --- a/packages/htmljs/package.js +++ /dev/null @@ -1,21 +0,0 @@ -Package.describe({ - summary: "Small library for expressing HTML trees", - version: '1.0.10' -}); - -Package.onUse(function (api) { - api.use('deps'); - api.export('HTML'); - - api.addFiles(['preamble.js', - 'visitors.js', - 'html.js']); -}); - -Package.onTest(function (api) { - api.use('htmljs'); - api.use('html-tools'); - api.use('tinytest'); - api.use('underscore'); - api.addFiles(['htmljs_test.js']); -}); diff --git a/packages/htmljs/preamble.js b/packages/htmljs/preamble.js deleted file mode 100644 index 160e038041..0000000000 --- a/packages/htmljs/preamble.js +++ /dev/null @@ -1,4 +0,0 @@ -HTML = {}; - -IDENTITY = function (x) { return x; }; -SLICE = Array.prototype.slice; diff --git a/packages/htmljs/visitors.js b/packages/htmljs/visitors.js deleted file mode 100644 index 15160e759a..0000000000 --- a/packages/htmljs/visitors.js +++ /dev/null @@ -1,331 +0,0 @@ -////////////////////////////// VISITORS - -// _assign is like _.extend or the upcoming Object.assign. -// Copy src's own, enumerable properties onto tgt and return -// tgt. -var _hasOwnProperty = Object.prototype.hasOwnProperty; -var _assign = function (tgt, src) { - for (var k in src) { - if (_hasOwnProperty.call(src, k)) - tgt[k] = src[k]; - } - return tgt; -}; - -HTML.Visitor = function (props) { - _assign(this, props); -}; - -HTML.Visitor.def = function (options) { - _assign(this.prototype, options); -}; - -HTML.Visitor.extend = function (options) { - var curType = this; - var subType = function HTMLVisitorSubtype(/*arguments*/) { - HTML.Visitor.apply(this, arguments); - }; - subType.prototype = new curType; - subType.extend = curType.extend; - subType.def = curType.def; - if (options) - _assign(subType.prototype, options); - return subType; -}; - -HTML.Visitor.def({ - visit: function (content/*, ...*/) { - if (content == null) - // null or undefined. - return this.visitNull.apply(this, arguments); - - if (typeof content === 'object') { - if (content.htmljsType) { - switch (content.htmljsType) { - case HTML.Tag.htmljsType: - return this.visitTag.apply(this, arguments); - case HTML.CharRef.htmljsType: - return this.visitCharRef.apply(this, arguments); - case HTML.Comment.htmljsType: - return this.visitComment.apply(this, arguments); - case HTML.Raw.htmljsType: - return this.visitRaw.apply(this, arguments); - default: - throw new Error("Unknown htmljs type: " + content.htmljsType); - } - } - - if (HTML.isArray(content)) - return this.visitArray.apply(this, arguments); - - return this.visitObject.apply(this, arguments); - - } else if ((typeof content === 'string') || - (typeof content === 'boolean') || - (typeof content === 'number')) { - return this.visitPrimitive.apply(this, arguments); - - } else if (typeof content === 'function') { - return this.visitFunction.apply(this, arguments); - } - - throw new Error("Unexpected object in htmljs: " + content); - - }, - visitNull: function (nullOrUndefined/*, ...*/) {}, - visitPrimitive: function (stringBooleanOrNumber/*, ...*/) {}, - visitArray: function (array/*, ...*/) {}, - visitComment: function (comment/*, ...*/) {}, - visitCharRef: function (charRef/*, ...*/) {}, - visitRaw: function (raw/*, ...*/) {}, - visitTag: function (tag/*, ...*/) {}, - visitObject: function (obj/*, ...*/) { - throw new Error("Unexpected object in htmljs: " + obj); - }, - visitFunction: function (fn/*, ...*/) { - throw new Error("Unexpected function in htmljs: " + fn); - } -}); - -HTML.TransformingVisitor = HTML.Visitor.extend(); -HTML.TransformingVisitor.def({ - visitNull: IDENTITY, - visitPrimitive: IDENTITY, - visitArray: function (array/*, ...*/) { - var argsCopy = SLICE.call(arguments); - var result = array; - for (var i = 0; i < array.length; i++) { - var oldItem = array[i]; - argsCopy[0] = oldItem; - var newItem = this.visit.apply(this, argsCopy); - if (newItem !== oldItem) { - // copy `array` on write - if (result === array) - result = array.slice(); - result[i] = newItem; - } - } - return result; - }, - visitComment: IDENTITY, - visitCharRef: IDENTITY, - visitRaw: IDENTITY, - visitObject: IDENTITY, - visitFunction: IDENTITY, - visitTag: function (tag/*, ...*/) { - var oldChildren = tag.children; - var argsCopy = SLICE.call(arguments); - argsCopy[0] = oldChildren; - var newChildren = this.visitChildren.apply(this, argsCopy); - - var oldAttrs = tag.attrs; - argsCopy[0] = oldAttrs; - var newAttrs = this.visitAttributes.apply(this, argsCopy); - - if (newAttrs === oldAttrs && newChildren === oldChildren) - return tag; - - var newTag = HTML.getTag(tag.tagName).apply(null, newChildren); - newTag.attrs = newAttrs; - return newTag; - }, - visitChildren: function (children/*, ...*/) { - return this.visitArray.apply(this, arguments); - }, - // Transform the `.attrs` property of a tag, which may be a dictionary, - // an array, or in some uses, a foreign object (such as - // a template tag). - visitAttributes: function (attrs/*, ...*/) { - if (HTML.isArray(attrs)) { - var argsCopy = SLICE.call(arguments); - var result = attrs; - for (var i = 0; i < attrs.length; i++) { - var oldItem = attrs[i]; - argsCopy[0] = oldItem; - var newItem = this.visitAttributes.apply(this, argsCopy); - if (newItem !== oldItem) { - // copy on write - if (result === attrs) - result = attrs.slice(); - result[i] = newItem; - } - } - return result; - } - - if (attrs && HTML.isConstructedObject(attrs)) { - throw new Error("The basic HTML.TransformingVisitor does not support " + - "foreign objects in attributes. Define a custom " + - "visitAttributes for this case."); - } - - var oldAttrs = attrs; - var newAttrs = oldAttrs; - if (oldAttrs) { - var attrArgs = [null, null]; - attrArgs.push.apply(attrArgs, arguments); - for (var k in oldAttrs) { - var oldValue = oldAttrs[k]; - attrArgs[0] = k; - attrArgs[1] = oldValue; - var newValue = this.visitAttribute.apply(this, attrArgs); - if (newValue !== oldValue) { - // copy on write - if (newAttrs === oldAttrs) - newAttrs = _assign({}, oldAttrs); - newAttrs[k] = newValue; - } - } - } - - return newAttrs; - }, - // Transform the value of one attribute name/value in an - // attributes dictionary. - visitAttribute: function (name, value, tag/*, ...*/) { - var args = SLICE.call(arguments, 2); - args[0] = value; - return this.visit.apply(this, args); - } -}); - - -HTML.ToTextVisitor = HTML.Visitor.extend(); -HTML.ToTextVisitor.def({ - visitNull: function (nullOrUndefined) { - return ''; - }, - visitPrimitive: function (stringBooleanOrNumber) { - var str = String(stringBooleanOrNumber); - if (this.textMode === HTML.TEXTMODE.RCDATA) { - return str.replace(/&/g, '&').replace(/`), we hackishly support HTML tags in markdown - // in templates by parsing them and stringifying them. - return this.visit(this.toHTML(tag)); - }, - visitObject: function (x) { - throw new Error("Unexpected object in htmljs in toText: " + x); - }, - toHTML: function (node) { - return HTML.toHTML(node); - } -}); - - - -HTML.ToHTMLVisitor = HTML.Visitor.extend(); -HTML.ToHTMLVisitor.def({ - visitNull: function (nullOrUndefined) { - return ''; - }, - visitPrimitive: function (stringBooleanOrNumber) { - var str = String(stringBooleanOrNumber); - return str.replace(/&/g, '&').replace(/'; - }, - visitCharRef: function (charRef) { - return charRef.html; - }, - visitRaw: function (raw) { - return raw.value; - }, - visitTag: function (tag) { - var attrStrs = []; - - var tagName = tag.tagName; - var children = tag.children; - - var attrs = tag.attrs; - if (attrs) { - attrs = HTML.flattenAttributes(attrs); - for (var k in attrs) { - if (k === 'value' && tagName === 'textarea') { - children = [attrs[k], children]; - } else { - var v = this.toText(attrs[k], HTML.TEXTMODE.ATTRIBUTE); - attrStrs.push(' ' + k + '="' + v + '"'); - } - } - } - - var startTag = '<' + tagName + attrStrs.join('') + '>'; - - var childStrs = []; - var content; - if (tagName === 'textarea') { - - for (var i = 0; i < children.length; i++) - childStrs.push(this.toText(children[i], HTML.TEXTMODE.RCDATA)); - - content = childStrs.join(''); - if (content.slice(0, 1) === '\n') - // TEXTAREA will absorb a newline, so if we see one, add - // another one. - content = '\n' + content; - - } else { - for (var i = 0; i < children.length; i++) - childStrs.push(this.visit(children[i])); - - content = childStrs.join(''); - } - - var result = startTag + content; - - if (children.length || ! HTML.isVoidElement(tagName)) { - // "Void" elements like BR are the only ones that don't get a close - // tag in HTML5. They shouldn't have contents, either, so we could - // throw an error upon seeing contents here. - result += ''; - } - - return result; - }, - visitObject: function (x) { - throw new Error("Unexpected object in htmljs in toHTML: " + x); - }, - toText: function (node, textMode) { - return HTML.toText(node, textMode); - } -}); diff --git a/packages/spacebars-compiler/.gitignore b/packages/spacebars-compiler/.gitignore deleted file mode 100644 index 677a6fc263..0000000000 --- a/packages/spacebars-compiler/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.build* diff --git a/packages/spacebars-compiler/README.md b/packages/spacebars-compiler/README.md deleted file mode 100644 index f0720673f6..0000000000 --- a/packages/spacebars-compiler/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# spacebars-compiler - -The Spacebars compiler that is invoked at build time to compile -templates to JavaScript. - -While this code is not normally ever shipped to the client, it can be -used at runtime on the server or the client by using the -`SpacebarsCompiler` symbol from this package. - -The `spacebars` package, in contrast, contains the `Spacebars` symbol -and the Spacebars runtime, which is shipped to the client as part of -the app. - -Read more about Spacebars, Blaze, and Meteor templating on the Blaze -[project page](https://www.meteor.com/blaze). diff --git a/packages/spacebars-compiler/codegen.js b/packages/spacebars-compiler/codegen.js deleted file mode 100644 index 3147a4a18a..0000000000 --- a/packages/spacebars-compiler/codegen.js +++ /dev/null @@ -1,389 +0,0 @@ -// ============================================================ -// Code-generation of template tags - -// The `CodeGen` class currently has no instance state, but in theory -// it could be useful to track per-function state, like whether we -// need to emit `var self = this` or not. -var CodeGen = SpacebarsCompiler.CodeGen = function () {}; - -var builtInBlockHelpers = SpacebarsCompiler._builtInBlockHelpers = { - 'if': 'Blaze.If', - 'unless': 'Blaze.Unless', - 'with': 'Spacebars.With', - 'each': 'Blaze.Each', - 'let': 'Blaze.Let' -}; - - -// Mapping of "macros" which, when preceded by `Template.`, expand -// to special code rather than following the lookup rules for dotted -// symbols. -var builtInTemplateMacros = { - // `view` is a local variable defined in the generated render - // function for the template in which `Template.contentBlock` or - // `Template.elseBlock` is invoked. - 'contentBlock': 'view.templateContentBlock', - 'elseBlock': 'view.templateElseBlock', - - // Confusingly, this makes `{{> Template.dynamic}}` an alias - // for `{{> __dynamic}}`, where "__dynamic" is the template that - // implements the dynamic template feature. - 'dynamic': 'Template.__dynamic', - - 'subscriptionsReady': 'view.templateInstance().subscriptionsReady()' -}; - -var additionalReservedNames = ["body", "toString", "instance", "constructor", - "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", - "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", - "__defineSetter__", "__lookupSetter__", "__proto__", "dynamic", - "registerHelper", "currentData", "parentData"]; - -// A "reserved name" can't be used as a