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 100% rename from packages/non-core/coffeescript/.npm/plugin/compileCoffeescript/npm-shrinkwrap.json rename to packages/non-core/coffeescript-compiler/.npm/package/npm-shrinkwrap.json diff --git a/packages/non-core/coffeescript-compiler/README.md b/packages/non-core/coffeescript-compiler/README.md new file mode 100644 index 0000000000..2a394f6f5b --- /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 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..ed228594cc --- /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. +CoffeeScriptCompiler = 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..fc394b7751 --- /dev/null +++ b/packages/non-core/coffeescript-compiler/package.js @@ -0,0 +1,21 @@ +Package.describe({ + name: 'coffeescript-compiler', + summary: 'Compiler for CoffeeScript code, supporting the coffeescript package', + version: '1.12.7_1' // Tracks version of NPM `coffeescript` module, with _1, _2 etc. +}); + +Npm.depends({ + 'coffeescript': '1.12.7', + 'source-map': '0.5.6' +}); + +Package.onUse(function (api) { + api.use('babel-compiler'); + api.use('ecmascript'); + + api.addFiles(['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 100% rename from packages/coffeescript-test-helper/package.js rename to packages/non-core/coffeescript-test-helper/package.js 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 fe0681a1ae..b23b98c88d 100644 --- a/packages/non-core/coffeescript/README.md +++ b/packages/non-core/coffeescript/README.md @@ -44,10 +44,6 @@ 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). @@ -59,5 +55,5 @@ 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 +./meteor test-packages 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 298d1c8a51..0634a95762 100644 --- a/packages/non-core/coffeescript/package.js +++ b/packages/non-core/coffeescript/package.js @@ -1,21 +1,25 @@ Package.describe({ - summary: "Javascript dialect with fewer braces and semicolons", - version: "1.12.7_1" + name: 'coffeescript', + summary: 'Javascript dialect with fewer braces and semicolons', + // This package version used to track the version of the NPM `coffeescript` + // module, but now the Meteor package `coffeescript-compiler` tracks that + // version; so in order for this to appear newer than the previous package + // version 1.12.6_1, we jump to 10+. + version: '10.0.1' }); Package.registerBuildPlugin({ - name: "compileCoffeescript", - use: ['caching-compiler', 'ecmascript'], - sources: ['plugin/compile-coffeescript.js'], + name: 'compile-coffeescript', + use: ['caching-compiler', 'coffeescript-compiler', 'ecmascript'], + sources: ['compile-coffeescript.js'], npmDependencies: { - "coffeescript": "1.12.7", - "source-map": "0.5.6" + 'coffeescript': '1.12.7', + 'source-map': '0.5.6' } }); 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+ @@ -23,7 +27,7 @@ Package.onUse(function (api) { // same runtime environment that the 'ecmascript' package provides. // 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('ecmascript-runtime', 'server'); api.imply('babel-runtime'); api.imply('promise'); }); 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 - }; -}