forked from meteor/meteor
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'devel' into minimongo-iterator
- Loading branch information
Showing
22 changed files
with
399 additions
and
284 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.npm |
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions
6
...n/compileCoffeescript/npm-shrinkwrap.json → ...compiler/.npm/package/npm-shrinkwrap.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 changes: 214 additions & 0 deletions
214
packages/non-core/coffeescript-compiler/coffeescript-compiler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
}; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions
4
packages/coffeescript-test-helper/package.js → ...-core/coffeescript-test-helper/package.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
.build* | ||
.npm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
Oops, something went wrong.