diff --git a/History.md b/History.md
index 9f2df019b5..e55edd7133 100644
--- a/History.md
+++ b/History.md
@@ -4,6 +4,12 @@
using `for...of` loops, spread operator, `yield*`, and destructuring assignments.
[PR #8888](https://github.com/meteor/meteor/pull/8888)
+* `meteor list --tree` can now be used to list all transitive package
+ dependencies (and versions) in an application. Weakly referenced dependencies
+ can also be listed by using the `--weak` option. For more information, run
+ `meteor help list`.
+ [PR #8936](https://github.com/meteor/meteor/pull/8936)
+
* The `star.json` manifest created within the root of a `meteor build` bundle
will now contain `nodeVersion` and `npmVersion` which will specify the exact
versions of Node.js and npm (respectively) which the Meteor release was
diff --git a/packages/non-core/coffeescript-compiler/.gitignore b/packages/non-core/coffeescript-compiler/.gitignore
new file mode 100644
index 0000000000..918ef5d781
--- /dev/null
+++ b/packages/non-core/coffeescript-compiler/.gitignore
@@ -0,0 +1 @@
+.npm
diff --git a/packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/.gitignore b/packages/non-core/coffeescript-compiler/.npm/package/.gitignore
similarity index 100%
rename from packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/.gitignore
rename to packages/non-core/coffeescript-compiler/.npm/package/.gitignore
diff --git a/packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/README b/packages/non-core/coffeescript-compiler/.npm/package/README
similarity index 100%
rename from packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/README
rename to packages/non-core/coffeescript-compiler/.npm/package/README
diff --git a/packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/npm-shrinkwrap.json b/packages/non-core/coffeescript-compiler/.npm/package/npm-shrinkwrap.json
similarity index 77%
rename from packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/npm-shrinkwrap.json
rename to packages/non-core/coffeescript-compiler/.npm/package/npm-shrinkwrap.json
index a24f8dcdc1..1f8aef812e 100644
--- a/packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/npm-shrinkwrap.json
+++ b/packages/non-core/coffeescript-compiler/.npm/package/npm-shrinkwrap.json
@@ -1,9 +1,9 @@
{
"dependencies": {
"coffeescript": {
- "version": "1.12.6",
- "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.6.tgz",
- "from": "coffeescript@1.12.6"
+ "version": "1.12.7",
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz",
+ "from": "coffeescript@1.12.7"
},
"source-map": {
"version": "0.5.6",
diff --git a/packages/non-core/coffeescript-compiler/README.md b/packages/non-core/coffeescript-compiler/README.md
new file mode 100644
index 0000000000..c561fe29e3
--- /dev/null
+++ b/packages/non-core/coffeescript-compiler/README.md
@@ -0,0 +1,17 @@
+# coffeescript-compiler
+[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/coffeescript-compiler) | [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/coffeescript-compiler)
+***
+
+This package supports the [`coffeescript`](../coffeescript/README.md) package,
+and any other packages that wish to compile CoffeeScript code into JavaScript.
+Like the [`babel-compiler`](../babel-compiler/README.md) package, the actual
+compilation is separated out from the build plugin so that packages besides
+the official `coffeescript` package can compile CoffeeScript code.
+
+### Testing This Package
+
+Testing the `coffeescript` package also tests this one:
+
+```bash
+./meteor test-packages packages/non-core/coffeescript
+```
diff --git a/packages/non-core/coffeescript-compiler/coffeescript-compiler.js b/packages/non-core/coffeescript-compiler/coffeescript-compiler.js
new file mode 100644
index 0000000000..52652d0518
--- /dev/null
+++ b/packages/non-core/coffeescript-compiler/coffeescript-compiler.js
@@ -0,0 +1,214 @@
+import { BabelCompiler } from 'meteor/babel-compiler';
+import CoffeeScript from 'coffeescript';
+import { SourceMapConsumer, SourceMapGenerator } from 'source-map';
+
+
+// The CoffeeScript compiler overrides Error.prepareStackTrace, mostly for the
+// use of coffee.run which we don't use. This conflicts with the tool's use of
+// Error.prepareStackTrace to properly show error messages in linked code.
+// Restore the tool's one after CoffeeScript clobbers it at import time.
+if (Error.METEOR_prepareStackTrace) {
+ Error.prepareStackTrace = Error.METEOR_prepareStackTrace;
+}
+
+
+// The CompileResult for this CachingCompiler is a {source, sourceMap} object.
+export class CoffeeScriptCompiler {
+ constructor() {
+ this.babelCompiler = new BabelCompiler({
+ // Prevent Babel from importing helpers from babel-runtime, since
+ // the CoffeeScript plugin does not imply the modules package, which
+ // means require may not be defined. Note that this in no way
+ // prevents CoffeeScript projects from using the modules package and
+ // putting require or import statements within backticks; it just
+ // won't happen automatically because of Babel.
+ runtime: false
+ });
+ }
+
+ getCompileOptions(inputFile) {
+ return {
+ bare: true,
+ filename: inputFile.getPathInPackage(),
+ literate: inputFile.getExtension() !== 'coffee',
+ // Return a source map.
+ sourceMap: true,
+ // This becomes the `file` field of the source map.
+ generatedFile: '/' + this.outputFilePath(inputFile),
+ // This becomes the `sources` field of the source map.
+ sourceFiles: [inputFile.getDisplayPath()],
+ };
+ }
+
+ outputFilePath(inputFile) {
+ return inputFile.getPathInPackage() + '.js';
+ }
+
+ compileOneFile(inputFile) {
+ const source = inputFile.getContentsAsString();
+ const compileOptions = this.getCompileOptions(inputFile);
+
+ let output;
+ try {
+ output = CoffeeScript.compile(source, compileOptions);
+ } catch (e) {
+ inputFile.error({
+ message: e.message,
+ line: e.location && (e.location.first_line + 1),
+ column: e.location && (e.location.first_column + 1)
+ });
+ return null;
+ }
+
+ let sourceMap = JSON.parse(output.v3SourceMap);
+ sourceMap.sourcesContent = [source];
+
+ output.js = this.stripExportedVars(
+ output.js,
+ inputFile.getDeclaredExports().map(e => e.name)
+ );
+
+ // CoffeeScript contains a handful of features that output as ES2015+,
+ // such as modules, generator functions, for…of, and tagged template
+ // literals. Because they’re too varied to detect, pass all CoffeeScript
+ // compiler output through the Babel compiler.
+ const doubleRoastedCoffee =
+ this.babelCompiler.processOneFileForTarget(inputFile, output.js);
+
+ if (doubleRoastedCoffee != null &&
+ doubleRoastedCoffee.data != null) {
+ output.js = doubleRoastedCoffee.data;
+
+ const coffeeSourceMap = doubleRoastedCoffee.sourceMap;
+
+ if (coffeeSourceMap) {
+ // Reference the compiled CoffeeScript file so that `applySourceMap`
+ // below can match it with the source map produced by the CoffeeScript
+ // compiler.
+ coffeeSourceMap.sources[0] = '/' + this.outputFilePath(inputFile);
+
+ // Combine the original CoffeeScript source map with the one
+ // produced by this.babelCompiler.processOneFileForTarget.
+ const smg = SourceMapGenerator.fromSourceMap(
+ new SourceMapConsumer(coffeeSourceMap)
+ );
+ smg.applySourceMap(new SourceMapConsumer(sourceMap));
+ sourceMap = smg.toJSON();
+ } else {
+ // If the .coffee file is contained by a node_modules directory,
+ // then BabelCompiler will not transpile it, and there will be
+ // no sourceMap, but that's fine because the original
+ // CoffeeScript sourceMap will still be valid.
+ }
+ }
+
+ return this.addSharedHeader(output.js, sourceMap);
+ }
+
+ stripExportedVars(source, exports) {
+ if (!exports || !exports.length)
+ return source;
+ const lines = source.split("\n");
+
+ // We make the following assumptions, based on the output of CoffeeScript
+ // 1.7.1.
+ // - The var declaration in question is not indented and is the first such
+ // var declaration. (CoffeeScript only produces one var line at each
+ // scope and there's only one top-level scope.) All relevant variables
+ // are actually on this line.
+ // - The user hasn't used a ###-comment containing a line that looks like
+ // a var line, to produce something like
+ // /* bla
+ // var foo;
+ // */
+ // before an actual var line. (ie, we do NOT attempt to figure out if
+ // we're inside a /**/ comment, which is produced by ### comments.)
+ // - The var in question is not assigned to in the declaration, nor are any
+ // other vars on this line. (CoffeeScript does produce some assignments
+ // but only for internal helpers generated by CoffeeScript, and they end
+ // up on subsequent lines.)
+ // XXX relax these assumptions by doing actual JS parsing (eg with jsparse).
+ // I'd do this now, but there's no easy way to "unparse" a jsparse AST.
+ // Or alternatively, hack the compiler to allow us to specify unbound
+ // symbols directly.
+
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i];
+ const match = /^var (.+)([,;])$/.exec(line);
+ if (!match)
+ continue;
+
+ // If there's an assignment on this line, we assume that there are ONLY
+ // assignments and that the var we are looking for is not declared. (Part
+ // of our strong assumption about the layout of this code.)
+ if (match[1].indexOf('=') !== -1)
+ continue;
+
+ // We want to replace the line with something no shorter, so that all
+ // records in the source map continue to point at valid
+ // characters.
+ function replaceLine(x) {
+ if (x.length >= lines[i].length) {
+ lines[i] = x;
+ } else {
+ lines[i] = x + new Array(1 + (lines[i].length - x.length)).join(' ');
+ }
+ }
+
+ let vars = match[1].split(', ').filter(v => exports.indexOf(v) === -1);
+ if (vars.length) {
+ replaceLine('var ' + vars.join(', ') + match[2]);
+ } else {
+ // We got rid of all the vars on this line. Drop the whole line if this
+ // didn't continue to the next line, otherwise keep just the 'var '.
+ if (match[2] === ';')
+ replaceLine('');
+ else
+ replaceLine('var');
+ }
+ break;
+ }
+
+ return lines.join('\n');
+ }
+
+ addSharedHeader(source, sourceMap) {
+ // We want the symbol "share" to be visible to all CoffeeScript files in the
+ // package (and shared between them), but not visible to JavaScript
+ // files. (That's because we don't want to introduce two competing ways to
+ // make package-local variables into JS ("share" vs assigning to non-var
+ // variables).) The following hack accomplishes that: "__coffeescriptShare"
+ // will be visible at the package level and "share" at the file level. This
+ // should work both in "package" mode where __coffeescriptShare will be added
+ // as a var in the package closure, and in "app" mode where it will end up as
+ // a global.
+ //
+ // This ends in a newline to make the source map easier to adjust.
+ const header = ("__coffeescriptShare = typeof __coffeescriptShare === 'object' " +
+ "? __coffeescriptShare : {}; " +
+ "var share = __coffeescriptShare;\n");
+
+ // If the file begins with "use strict", we need to keep that as the first
+ // statement.
+ const processedSource = source.replace(/^(?:((['"])use strict\2;)\n)?/, (match, useStrict) => {
+ if (match) {
+ // There's a "use strict"; we keep this as the first statement and insert
+ // our header at the end of the line that it's on. This doesn't change
+ // line numbers or the part of the line that previous may have been
+ // annotated, so we don't need to update the source map.
+ return useStrict + ' ' + header;
+ } else {
+ // There's no use strict, so we can just add the header at the very
+ // beginning. This adds a line to the file, so we update the source map to
+ // add a single un-annotated line to the beginning.
+ sourceMap.mappings = ';' + sourceMap.mappings;
+ return header;
+ }
+ });
+ return {
+ source: processedSource,
+ sourceMap: sourceMap
+ };
+ }
+
+}
diff --git a/packages/non-core/coffeescript-compiler/package.js b/packages/non-core/coffeescript-compiler/package.js
new file mode 100644
index 0000000000..0696cdfc62
--- /dev/null
+++ b/packages/non-core/coffeescript-compiler/package.js
@@ -0,0 +1,23 @@
+Package.describe({
+ name: 'coffeescript-compiler',
+ summary: 'Compiler for CoffeeScript code, supporting the coffeescript package',
+ // This version of NPM `coffeescript` module, with _1, _2 etc.
+ // If you change this, make sure to also update ../coffeescript/package.js to match.
+ version: '1.12.7_1'
+});
+
+Npm.depends({
+ 'coffeescript': '1.12.7',
+ 'source-map': '0.5.6'
+});
+
+Package.onUse(function (api) {
+ api.use('babel-compiler@6.19.4');
+ api.use('ecmascript@0.8.2');
+
+ api.mainModule('coffeescript-compiler.js', 'server');
+
+ api.export('CoffeeScriptCompiler', 'server');
+});
+
+// See `coffeescript` package for tests.
diff --git a/packages/coffeescript-test-helper/.gitignore b/packages/non-core/coffeescript-test-helper/.gitignore
similarity index 100%
rename from packages/coffeescript-test-helper/.gitignore
rename to packages/non-core/coffeescript-test-helper/.gitignore
diff --git a/packages/coffeescript-test-helper/README.md b/packages/non-core/coffeescript-test-helper/README.md
similarity index 100%
rename from packages/coffeescript-test-helper/README.md
rename to packages/non-core/coffeescript-test-helper/README.md
diff --git a/packages/coffeescript-test-helper/exporting.coffee b/packages/non-core/coffeescript-test-helper/exporting.coffee
similarity index 100%
rename from packages/coffeescript-test-helper/exporting.coffee
rename to packages/non-core/coffeescript-test-helper/exporting.coffee
diff --git a/packages/coffeescript-test-helper/package.js b/packages/non-core/coffeescript-test-helper/package.js
similarity index 80%
rename from packages/coffeescript-test-helper/package.js
rename to packages/non-core/coffeescript-test-helper/package.js
index b79b10367e..1789bee55a 100644
--- a/packages/coffeescript-test-helper/package.js
+++ b/packages/non-core/coffeescript-test-helper/package.js
@@ -1,10 +1,10 @@
Package.describe({
summary: "Used by the coffeescript package's tests",
- version: "1.0.8"
+ version: "1.0.9"
});
Package.onUse(function (api) {
- api.use('coffeescript', ['client', 'server']);
+ api.use('coffeescript@1.12.7', ['client', 'server']);
api.export('COFFEESCRIPT_EXPORTED');
api.export('COFFEESCRIPT_EXPORTED_ONE_MORE');
api.export('COFFEESCRIPT_EXPORTED_WITH_BACKTICKS');
diff --git a/packages/non-core/coffeescript/.gitignore b/packages/non-core/coffeescript/.gitignore
index 677a6fc263..c01644335c 100644
--- a/packages/non-core/coffeescript/.gitignore
+++ b/packages/non-core/coffeescript/.gitignore
@@ -1 +1,2 @@
.build*
+.npm
diff --git a/packages/non-core/coffeescript/README.md b/packages/non-core/coffeescript/README.md
index 711ff02abd..040656445d 100644
--- a/packages/non-core/coffeescript/README.md
+++ b/packages/non-core/coffeescript/README.md
@@ -44,10 +44,16 @@ Here's how CoffeeScript works with Meteor's namespacing.
for a value that is shared between all CoffeeScript code in a
package, but doesn't escape that package.
-Heavy CoffeeScript users, please let us know how this arrangement
-works for you, whether `share` is helpful for you, and anything else
-you'd like to see changed.
-
### Modules and CoffeeScript
See [Modules » CoffeeScript Syntax](http://docs.meteor.com/packages/modules.html#CoffeeScript).
+
+### Testing This Package
+
+Follow the [instructions](https://github.com/meteor/meteor/blob/devel/Development.md#tests)
+to check out the Meteor repo and run `test-packages`.
+Once you can do that successfully, to test the `coffeescript` package run:
+
+```bash
+./meteor test-packages packages/non-core/coffeescript
+```
diff --git a/packages/non-core/coffeescript/compile-coffeescript.js b/packages/non-core/coffeescript/compile-coffeescript.js
new file mode 100644
index 0000000000..c8c940b770
--- /dev/null
+++ b/packages/non-core/coffeescript/compile-coffeescript.js
@@ -0,0 +1,48 @@
+Plugin.registerCompiler({
+ extensions: ['coffee', 'litcoffee', 'coffee.md']
+}, () => new CachedCoffeeScriptCompiler());
+
+
+// The CompileResult for this CachingCompiler is a {source, sourceMap} object.
+class CachedCoffeeScriptCompiler extends CachingCompiler {
+ constructor() {
+ super({
+ compilerName: 'coffeescript',
+ defaultCacheSize: 1024*1024*10,
+ });
+
+ this.coffeeScriptCompiler = new CoffeeScriptCompiler();
+ }
+
+ getCacheKey(inputFile) {
+ return [
+ inputFile.getSourceHash(),
+ inputFile.getDeclaredExports(),
+ this.coffeeScriptCompiler.getCompileOptions(inputFile),
+ ];
+ }
+
+ setDiskCacheDirectory(cacheDir) {
+ this.coffeeScriptCompiler.babelCompiler.setDiskCacheDirectory(cacheDir);
+ return super.setDiskCacheDirectory(cacheDir);
+ }
+
+ compileOneFile(inputFile) {
+ return this.coffeeScriptCompiler.compileOneFile(inputFile);
+ }
+
+ addCompileResult(inputFile, sourceWithMap) {
+ inputFile.addJavaScript({
+ path: this.coffeeScriptCompiler.outputFilePath(inputFile),
+ sourcePath: inputFile.getPathInPackage(),
+ data: sourceWithMap.source,
+ sourceMap: sourceWithMap.sourceMap,
+ bare: inputFile.getFileOptions().bare
+ });
+ }
+
+ compileResultSize(sourceWithMap) {
+ return sourceWithMap.source.length +
+ this.sourceMapSize(sourceWithMap.sourceMap);
+ }
+}
diff --git a/packages/non-core/coffeescript/package.js b/packages/non-core/coffeescript/package.js
index 5c7601eb1f..a4b4511c76 100644
--- a/packages/non-core/coffeescript/package.js
+++ b/packages/non-core/coffeescript/package.js
@@ -1,31 +1,32 @@
Package.describe({
- summary: "Javascript dialect with fewer braces and semicolons",
- version: "1.12.6_1"
+ name: 'coffeescript',
+ summary: 'Javascript dialect with fewer braces and semicolons',
+ // This package version should track the version of the `coffeescript-compiler`
+ // package, because people will likely only have this one added to their apps;
+ // so bumping the version of this package will be how they get newer versions
+ // of `coffeescript-compiler`. If you change this, make sure to also update
+ // ../coffeescript-compiler/package.js to match.
+ version: '1.12.7_1'
});
Package.registerBuildPlugin({
- name: "compileCoffeescript",
- use: ['caching-compiler', 'ecmascript'],
- sources: ['plugin/compile-coffeescript.js'],
- npmDependencies: {
- "coffeescript": "1.12.6",
- "source-map": "0.5.6"
- }
+ name: 'compile-coffeescript',
+ use: ['caching-compiler@1.1.9', 'ecmascript@0.8.2', 'coffeescript-compiler@=1.12.7_1'],
+ sources: ['compile-coffeescript.js']
});
Package.onUse(function (api) {
api.use('isobuild:compiler-plugin@1.0.0');
- api.use('babel-compiler');
// Because the CoffeeScript plugin now calls
// BabelCompiler.prototype.processOneFileForTarget for any ES2015+
// JavaScript or JavaScript enclosed by backticks, it must provide the
// same runtime environment that the 'ecmascript' package provides.
- // The following api.imply calls should match those in ../ecmascript/package.js,
+ // The following api.imply calls should match those in ../../ecmascript/package.js,
// except that coffeescript does not api.imply('modules').
- api.imply('ecmascript-runtime');
- api.imply('babel-runtime');
- api.imply('promise');
+ api.imply('ecmascript-runtime@0.4.1', 'server');
+ api.imply('babel-runtime@1.0.1');
+ api.imply('promise@0.8.9');
});
Package.onTest(function (api) {
diff --git a/packages/non-core/coffeescript/plugin/compile-coffeescript.js b/packages/non-core/coffeescript/plugin/compile-coffeescript.js
deleted file mode 100644
index 03abcbe842..0000000000
--- a/packages/non-core/coffeescript/plugin/compile-coffeescript.js
+++ /dev/null
@@ -1,252 +0,0 @@
-import {
- SourceMapConsumer,
- SourceMapGenerator,
-} from 'source-map';
-import coffee from 'coffeescript';
-import { BabelCompiler } from 'meteor/babel-compiler';
-
-// The CoffeeScript compiler overrides Error.prepareStackTrace, mostly for the
-// use of coffee.run which we don't use. This conflicts with the tool's use of
-// Error.prepareStackTrace to properly show error messages in linked code.
-// Restore the tool's one after CoffeeScript clobbers it at import time.
-if (Error.METEOR_prepareStackTrace) {
- Error.prepareStackTrace = Error.METEOR_prepareStackTrace;
-}
-
-Plugin.registerCompiler({
- extensions: ['coffee', 'litcoffee', 'coffee.md']
-}, () => new CoffeeCompiler());
-
-// The CompileResult for this CachingCompiler is a {source, sourceMap} object.
-
-export class CoffeeCompiler extends CachingCompiler {
- constructor() {
- super({
- compilerName: 'coffeescript',
- defaultCacheSize: 1024*1024*10,
- });
-
- this.babelCompiler = new BabelCompiler({
- // Prevent Babel from importing helpers from babel-runtime, since
- // the CoffeeScript plugin does not imply the modules package, which
- // means require may not be defined. Note that this in no way
- // prevents CoffeeScript projects from using the modules package and
- // putting require or import statements within backticks; it just
- // won't happen automatically because of Babel.
- runtime: false
- });
- }
-
- _getCompileOptions(inputFile) {
- return {
- bare: true,
- filename: inputFile.getPathInPackage(),
- literate: inputFile.getExtension() !== 'coffee',
- // Return a source map.
- sourceMap: true,
- // This becomes the "file" field of the source map.
- generatedFile: '/' + this._outputFilePath(inputFile),
- // This becomes the "sources" field of the source map.
- sourceFiles: [inputFile.getDisplayPath()],
- };
- }
-
- _outputFilePath(inputFile) {
- return inputFile.getPathInPackage() + '.js';
- }
-
- getCacheKey(inputFile) {
- return [
- inputFile.getSourceHash(),
- inputFile.getDeclaredExports(),
- this._getCompileOptions(inputFile),
- ];
- }
-
- setDiskCacheDirectory(cacheDir) {
- this.babelCompiler.setDiskCacheDirectory(cacheDir);
- return super.setDiskCacheDirectory(cacheDir);
- }
-
- compileOneFile(inputFile) {
- const source = inputFile.getContentsAsString();
- const compileOptions = this._getCompileOptions(inputFile);
-
- let output;
- try {
- output = coffee.compile(source, compileOptions);
- } catch (e) {
- inputFile.error({
- message: e.message,
- line: e.location && (e.location.first_line + 1),
- column: e.location && (e.location.first_column + 1)
- });
- return null;
- }
-
- let sourceMap = JSON.parse(output.v3SourceMap);
- sourceMap.sourcesContent = [source];
-
- output.js = stripExportedVars(
- output.js,
- inputFile.getDeclaredExports().map(e => e.name)
- );
-
- // CoffeeScript contains a handful of features that output as ES2015+,
- // such as modules, generator functions, for…of, and tagged template
- // literals. Because they’re too varied to detect, pass all CoffeeScript
- // compiler output through the Babel compiler.
- const doubleRoastedCoffee =
- this.babelCompiler.processOneFileForTarget(inputFile, output.js);
-
- if (doubleRoastedCoffee != null &&
- doubleRoastedCoffee.data != null) {
- output.js = doubleRoastedCoffee.data;
-
- const coffeeSourceMap = doubleRoastedCoffee.sourceMap;
-
- if (coffeeSourceMap) {
- // Reference the compiled CoffeeScript file so that `applySourceMap`
- // below can match it with the source map produced by the CoffeeScript
- // compiler.
- coffeeSourceMap.sources[0] = '/' + this._outputFilePath(inputFile);
-
- // Combine the original CoffeeScript source map with the one
- // produced by this.babelCompiler.processOneFileForTarget.
- const smg = SourceMapGenerator.fromSourceMap(
- new SourceMapConsumer(coffeeSourceMap)
- );
- smg.applySourceMap(new SourceMapConsumer(sourceMap));
- sourceMap = smg.toJSON();
- } else {
- // If the .coffee file is contained by a node_modules directory,
- // then BabelCompiler will not transpile it, and there will be
- // no sourceMap, but that's fine because the original
- // CoffeeScript sourceMap will still be valid.
- }
- }
-
- return addSharedHeader(output.js, sourceMap);
- }
-
- addCompileResult(inputFile, sourceWithMap) {
- inputFile.addJavaScript({
- path: this._outputFilePath(inputFile),
- sourcePath: inputFile.getPathInPackage(),
- data: sourceWithMap.source,
- sourceMap: sourceWithMap.sourceMap,
- bare: inputFile.getFileOptions().bare
- });
- }
-
- compileResultSize(sourceWithMap) {
- return sourceWithMap.source.length +
- this.sourceMapSize(sourceWithMap.sourceMap);
- }
-}
-
-function stripExportedVars(source, exports) {
- if (!exports || !exports.length)
- return source;
- const lines = source.split("\n");
-
- // We make the following assumptions, based on the output of CoffeeScript
- // 1.7.1.
- // - The var declaration in question is not indented and is the first such
- // var declaration. (CoffeeScript only produces one var line at each
- // scope and there's only one top-level scope.) All relevant variables
- // are actually on this line.
- // - The user hasn't used a ###-comment containing a line that looks like
- // a var line, to produce something like
- // /* bla
- // var foo;
- // */
- // before an actual var line. (ie, we do NOT attempt to figure out if
- // we're inside a /**/ comment, which is produced by ### comments.)
- // - The var in question is not assigned to in the declaration, nor are any
- // other vars on this line. (CoffeeScript does produce some assignments
- // but only for internal helpers generated by CoffeeScript, and they end
- // up on subsequent lines.)
- // XXX relax these assumptions by doing actual JS parsing (eg with jsparse).
- // I'd do this now, but there's no easy way to "unparse" a jsparse AST.
- // Or alternatively, hack the compiler to allow us to specify unbound
- // symbols directly.
-
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
- const match = /^var (.+)([,;])$/.exec(line);
- if (!match)
- continue;
-
- // If there's an assignment on this line, we assume that there are ONLY
- // assignments and that the var we are looking for is not declared. (Part
- // of our strong assumption about the layout of this code.)
- if (match[1].indexOf('=') !== -1)
- continue;
-
- // We want to replace the line with something no shorter, so that all
- // records in the source map continue to point at valid
- // characters.
- function replaceLine(x) {
- if (x.length >= lines[i].length) {
- lines[i] = x;
- } else {
- lines[i] = x + new Array(1 + (lines[i].length - x.length)).join(' ');
- }
- }
-
- let vars = match[1].split(', ').filter(v => exports.indexOf(v) === -1);
- if (vars.length) {
- replaceLine('var ' + vars.join(', ') + match[2]);
- } else {
- // We got rid of all the vars on this line. Drop the whole line if this
- // didn't continue to the next line, otherwise keep just the 'var '.
- if (match[2] === ';')
- replaceLine('');
- else
- replaceLine('var');
- }
- break;
- }
-
- return lines.join('\n');
-}
-
-function addSharedHeader(source, sourceMap) {
- // We want the symbol "share" to be visible to all CoffeeScript files in the
- // package (and shared between them), but not visible to JavaScript
- // files. (That's because we don't want to introduce two competing ways to
- // make package-local variables into JS ("share" vs assigning to non-var
- // variables).) The following hack accomplishes that: "__coffeescriptShare"
- // will be visible at the package level and "share" at the file level. This
- // should work both in "package" mode where __coffeescriptShare will be added
- // as a var in the package closure, and in "app" mode where it will end up as
- // a global.
- //
- // This ends in a newline to make the source map easier to adjust.
- const header = ("__coffeescriptShare = typeof __coffeescriptShare === 'object' " +
- "? __coffeescriptShare : {}; " +
- "var share = __coffeescriptShare;\n");
-
- // If the file begins with "use strict", we need to keep that as the first
- // statement.
- const processedSource = source.replace(/^(?:((['"])use strict\2;)\n)?/, (match, useStrict) => {
- if (match) {
- // There's a "use strict"; we keep this as the first statement and insert
- // our header at the end of the line that it's on. This doesn't change
- // line numbers or the part of the line that previous may have been
- // annotated, so we don't need to update the source map.
- return useStrict + ' ' + header;
- } else {
- // There's no use strict, so we can just add the header at the very
- // beginning. This adds a line to the file, so we update the source map to
- // add a single un-annotated line to the beginning.
- sourceMap.mappings = ';' + sourceMap.mappings;
- return header;
- }
- });
- return {
- source: processedSource,
- sourceMap: sourceMap
- };
-}
diff --git a/packages/test-in-browser/driver.css b/packages/test-in-browser/driver.css
index 1530170097..0251f37d4f 100644
--- a/packages/test-in-browser/driver.css
+++ b/packages/test-in-browser/driver.css
@@ -151,4 +151,8 @@ body {
#current-client-test {
color: #ccc;
margin-right: 15px;
-}
\ No newline at end of file
+}
+
+.failedTests {
+ color: #900; /* red */
+}
diff --git a/packages/test-in-browser/driver.html b/packages/test-in-browser/driver.html
index 5e4b272e0c..fbd3ec10e1 100644
--- a/packages/test-in-browser/driver.html
+++ b/packages/test-in-browser/driver.html
@@ -1,6 +1,7 @@
+ WARNING: The following uncaught errors might be
+ preventing some client tests from running.
+
+
+ {{#each uncaughtErrors}}
+
{{this}}
+ {{/each}}
+
+
+
+
+ {{/if}}
+
+
-
-
- {{#each failedTests}}
-
{{this}}
- {{/each}}
-
-
+ {{#if failedTests}}
+
+
+
+ {{#each failedTests}}
+
{{this}}
+ {{/each}}
+
+
+
+ {{/if}}
diff --git a/packages/test-in-browser/driver.js b/packages/test-in-browser/driver.js
index 2602f56923..7600362060 100644
--- a/packages/test-in-browser/driver.js
+++ b/packages/test-in-browser/driver.js
@@ -35,6 +35,12 @@ var topLevelGroupsDep = new Tracker.Dependency;
// - dep: Tracker.Dependency object for this test. fires when the test completes.
var resultTree = [];
+Session.set("uncaughtErrors", []);
+window.onerror = (message, source, line) => {
+ const uncaughtErrors = new Set(Session.get("uncaughtErrors"));
+ uncaughtErrors.add(message);
+ Session.set("uncaughtErrors", Array.from(uncaughtErrors));
+};
Session.setDefault("groupPath", ["tinytest"]);
Session.set("rerunScheduled", false);
@@ -359,6 +365,13 @@ Template.groupNav.onRendered(function () {
};
});
+//// Template - uncaughtErrors
+
+Template.uncaughtErrors.helpers({
+ uncaughtErrors() {
+ return Session.get("uncaughtErrors");
+ }
+});
//// Template - failedTests
diff --git a/packages/test-in-browser/package.js b/packages/test-in-browser/package.js
index 36cba98c44..6c5e80b7c8 100644
--- a/packages/test-in-browser/package.js
+++ b/packages/test-in-browser/package.js
@@ -1,10 +1,11 @@
Package.describe({
summary: "Run tests interactively in the browser",
- version: '1.0.13',
+ version: '1.0.14',
documentation: null
});
Package.onUse(function (api) {
+ api.use('ecmascript');
// XXX this should go away, and there should be a clean interface
// that tinytest and the driver both implement?
api.use('tinytest');
diff --git a/tools/cli/help.txt b/tools/cli/help.txt
index d397e731c7..88dd7c735e 100644
--- a/tools/cli/help.txt
+++ b/tools/cli/help.txt
@@ -584,6 +584,10 @@ Options:
test app rebuild.
--extra-packages Run with additional packages (comma separated, for example:
--extra-packages "package-name1, package-name2@1.2.3")
+ --driver-package Name of the optional test driver package to use to run
+ tests and display results. For example:
+ --driver-package practicalmeteor:mocha
+
>>> test
Test the application
Usage: meteor test --driver-package [options]
@@ -638,6 +642,9 @@ Options:
--verbose Print all output from builds logs.
--extra-packages Run with additional packages (comma separated, for example:
--extra-packages "package-name1, package-name2@1.2.3")
+ --driver-package Name of the optional test driver package to use to run
+ tests and display results. For example:
+ --driver-package practicalmeteor:mocha
>>> self-test
Run tests of the 'meteor' tool.