Merge pull request #3323 from divmain/master

Source-map support for multiple input source files
This commit is contained in:
Amjad Masad
2016-03-07 11:57:59 -08:00
11 changed files with 208 additions and 7 deletions

View File

@@ -44,4 +44,41 @@ name | type | default | description
sourceMaps | boolean | `false` | Enable generating source maps
sourceMapTarget | string | | The filename of the generated code that the source map will be associated with
sourceRoot | string | | A root for all relative URLs in the source map
sourceFileName | string | | The filename for the source code (i.e. the code in the `code` argument)
sourceFileName | string | | The filename for the source code (i.e. the code in the `code` argument). This will only be used if `code` is a string.
## AST from Multiple Sources
In most cases, Babel does a 1:1 transformation of input-file to output-file. However,
you may be dealing with AST constructed from multiple sources - JS files, templates, etc.
If this is the case, and you want the sourcemaps to reflect the correct sources, you'll need
to make some changes to your code.
First, each node with a `loc` property (which indicates that node's original placement in the
source document) must also include a `loc.filename` property, set to the source filename.
Second, you should pass an object to `generate` as the `code` parameter. Keys
should be the source filenames, and values should be the source content.
Here's an example of what that might look like:
```js
import {parse} from 'babylon';
import traverse from "babel-traverse";
import generate from 'babel-generator';
const a = 'var a = 1;';
const b = 'var b = 2;';
const astA = parse(a, { filename: 'a.js' });
const astB = parse(b, { filename: 'b.js' });
const ast = {
type: 'Program',
body: [].concat(astA.body, ast2.body)
};
const { code, map } = generate(ast, { /* options */ }, {
'a.js': a,
'b.js': b
});
// Sourcemap will point to both a.js and b.js where appropriate.
```

View File

@@ -71,7 +71,7 @@ export class CodeGenerator extends Printer {
static normalizeOptions(code, opts, tokens) {
let style = " ";
if (code) {
if (code && typeof code === "string") {
let indent = detectIndent(code).indent;
if (indent && indent !== " ") style = indent;
}

View File

@@ -17,7 +17,13 @@ export default class SourceMap {
sourceRoot: opts.sourceRoot
});
this.map.setSourceContent(opts.sourceFileName, code);
if (typeof code === "string") {
this.map.setSourceContent(opts.sourceFileName, code);
} else if (typeof code === "object") {
Object.keys(code).forEach((sourceFileName) => {
this.map.setSourceContent(sourceFileName, code[sourceFileName]);
});
}
} else {
this.map = null;
}
@@ -68,7 +74,7 @@ export default class SourceMap {
}
this.last = {
source: this.opts.sourceFileName,
source: loc.filename || this.opts.sourceFileName,
generated: generated,
original: original
};

View File

@@ -17,6 +17,44 @@ suite("generation", function () {
assert.ok(t.VISITOR_KEYS[type], type + " should not exist");
});
});
test("multiple sources", function () {
var sources = {
"a.js": "function hi (msg) { console.log(msg); }\n",
"b.js": "hi('hello');\n"
};
var parsed = _.keys(sources).reduce(function (_parsed, filename) {
_parsed[filename] = parse(sources[filename], { sourceFilename: filename });
return _parsed;
}, {});
var combinedAst = {
"type": "File",
"program": {
"type": "Program",
"sourceType": "module",
"body": [].concat(parsed["a.js"].program.body, parsed["b.js"].program.body)
}
};
var generated = generate.default(combinedAst, { sourceMaps: true }, sources);
chai.expect(generated.map).to.deep.equal({
version: 3,
sources: [ 'a.js', 'b.js' ],
names: [],
mappings: 'AAAA,SAAS,EAAT,CAAa,GAAb,EAAkB;AAAE,UAAQ,GAAR,CAAY,GAAZ,EAAF;CAAlB;;GCAG,OAAH',
sourcesContent: [
'function hi (msg) { console.log(msg); }\n',
'hi(\'hello\');\n'
]
}, "sourcemap was incorrectly generated");
chai.expect(generated.code).to.equal(
"function hi(msg) {\n console.log(msg);\n}\n\nhi('hello');",
"code was incorrectly generated"
);
});
});