mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'devel' into minimongo-iterator
This commit is contained in:
@@ -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
|
||||
|
||||
1
packages/non-core/coffeescript-compiler/.gitignore
vendored
Normal file
1
packages/non-core/coffeescript-compiler/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.npm
|
||||
@@ -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",
|
||||
17
packages/non-core/coffeescript-compiler/README.md
Normal file
17
packages/non-core/coffeescript-compiler/README.md
Normal file
@@ -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
|
||||
```
|
||||
214
packages/non-core/coffeescript-compiler/coffeescript-compiler.js
Normal file
214
packages/non-core/coffeescript-compiler/coffeescript-compiler.js
Normal file
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
23
packages/non-core/coffeescript-compiler/package.js
Normal file
23
packages/non-core/coffeescript-compiler/package.js
Normal file
@@ -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.
|
||||
@@ -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');
|
||||
1
packages/non-core/coffeescript/.gitignore
vendored
1
packages/non-core/coffeescript/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.build*
|
||||
.npm
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
48
packages/non-core/coffeescript/compile-coffeescript.js
Normal file
48
packages/non-core/coffeescript/compile-coffeescript.js
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -151,4 +151,8 @@ body {
|
||||
#current-client-test {
|
||||
color: #ccc;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.failedTests {
|
||||
color: #900; /* red */
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template name="testInBrowserBody">
|
||||
<div class="container-fluid">
|
||||
{{> navBars}}
|
||||
{{> uncaughtErrors}}
|
||||
{{> failedTests}}
|
||||
{{> testTable}}
|
||||
</div>
|
||||
@@ -71,14 +72,38 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="uncaughtErrors">
|
||||
{{#if uncaughtErrors}}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="alert alert-danger">
|
||||
<p>
|
||||
<strong>WARNING:</strong> The following uncaught errors might be
|
||||
preventing some client tests from running.
|
||||
</p>
|
||||
<ul>
|
||||
{{#each uncaughtErrors}}
|
||||
<li>{{this}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="failedTests">
|
||||
<div class="row-fluid"><div class="span12">
|
||||
<ul class="failedTests">
|
||||
{{#each failedTests}}
|
||||
<li>{{this}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div></div>
|
||||
{{#if failedTests}}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<ul class="failedTests">
|
||||
{{#each failedTests}}
|
||||
<li>{{this}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="testTable">
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 <driver> [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.
|
||||
|
||||
Reference in New Issue
Block a user