Skip to content

Commit 2d7d5a0

Browse files
authored
Merge pull request webpack#6349 from webpack/parser_source_type
Refactor how source type is handled by the parser
2 parents 2270596 + 86e6edf commit 2d7d5a0

File tree

4 files changed

+66
-70
lines changed

4 files changed

+66
-70
lines changed

lib/JavascriptModulesPlugin.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ class JavascriptModulesPlugin {
1111
compiler.hooks.compilation.tap("JavascriptModulesPlugin", (compilation, {
1212
normalModuleFactory
1313
}) => {
14-
const createParser = () => {
15-
return new Parser();
16-
};
17-
18-
normalModuleFactory.hooks.createParser.for("javascript/auto").tap("JavascriptModulesPlugin", createParser);
19-
normalModuleFactory.hooks.createParser.for("javascript/dynamic").tap("JavascriptModulesPlugin", createParser);
20-
normalModuleFactory.hooks.createParser.for("javascript/esm").tap("JavascriptModulesPlugin", createParser);
14+
normalModuleFactory.hooks.createParser.for("javascript/auto").tap("JavascriptModulesPlugin", options => {
15+
return new Parser(options, "auto");
16+
});
17+
normalModuleFactory.hooks.createParser.for("javascript/dynamic").tap("JavascriptModulesPlugin", options => {
18+
return new Parser(options, "script");
19+
});
20+
normalModuleFactory.hooks.createParser.for("javascript/esm").tap("JavascriptModulesPlugin", options => {
21+
return new Parser(options, "module");
22+
});
2123
});
2224
}
2325
}

lib/NormalModuleFactory.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class NormalModuleFactory extends Tapable {
8888
this.ruleSet = new RuleSet(options.defaultRules.concat(options.rules));
8989
this.cachePredicate = typeof options.unsafeCache === "function" ? options.unsafeCache : Boolean.bind(null, options.unsafeCache);
9090
this.context = context || "";
91-
this.parserCache = {};
91+
this.parserCache = Object.create(null);
9292
this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
9393
let resolver = this.hooks.resolver.call(null);
9494

@@ -332,14 +332,13 @@ class NormalModuleFactory extends Tapable {
332332
else
333333
ident = JSON.stringify([type, parserOptions]);
334334
}
335-
const parser = this.parserCache[ident];
336-
if(parser)
337-
return parser;
335+
if(ident in this.parserCache) {
336+
return this.parserCache[ident];
337+
}
338338
return this.parserCache[ident] = this.createParser(type, parserOptions);
339339
}
340340

341-
createParser(type, parserOptions) {
342-
parserOptions = parserOptions || {};
341+
createParser(type, parserOptions = {}) {
343342
const parser = this.hooks.createParser.for(type).call(parserOptions);
344343
if(!parser) {
345344
throw new Error(`No parser registered for ${type}`);

lib/Parser.js

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,19 @@ const joinRanges = (startRange, endRange) => {
2121
return [startRange[0], endRange[1]];
2222
};
2323

24-
const ECMA_VERSION = 2017;
25-
26-
const POSSIBLE_AST_OPTIONS = [{
24+
const defaultParserOptions = {
2725
ranges: true,
2826
locations: true,
29-
ecmaVersion: ECMA_VERSION,
27+
ecmaVersion: 2017,
3028
sourceType: "module",
29+
onComment: null,
3130
plugins: {
3231
dynamicImport: true
3332
}
34-
}, {
35-
ranges: true,
36-
locations: true,
37-
ecmaVersion: ECMA_VERSION,
38-
sourceType: "script",
39-
plugins: {
40-
dynamicImport: true
41-
}
42-
}];
33+
};
4334

4435
class Parser extends Tapable {
45-
constructor(options) {
36+
constructor(options, sourceType = "auto") {
4637
super();
4738
this.hooks = {
4839
evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])),
@@ -116,6 +107,7 @@ class Parser extends Tapable {
116107
}
117108
});
118109
this.options = options;
110+
this.sourceType = sourceType;
119111
this.scope = undefined;
120112
this.state = undefined;
121113
this.comments = undefined;
@@ -1761,37 +1753,18 @@ class Parser extends Tapable {
17611753

17621754
parse(source, initialState) {
17631755
let ast;
1764-
let comments = [];
1756+
let comments;
17651757
if(typeof source === "object" && source !== null) {
17661758
ast = source;
17671759
comments = source.comments;
1768-
}
1769-
for(let i = 0, len = POSSIBLE_AST_OPTIONS.length; i < len; i++) {
1770-
if(!ast) {
1771-
try {
1772-
comments.length = 0;
1773-
POSSIBLE_AST_OPTIONS[i].onComment = comments;
1774-
ast = acorn.parse(source, POSSIBLE_AST_OPTIONS[i]);
1775-
} catch(e) {
1776-
// ignore the error
1777-
}
1778-
}
1779-
}
1780-
if(!ast) {
1781-
// for the error
1782-
ast = acorn.parse(source, {
1783-
ranges: true,
1784-
locations: true,
1785-
ecmaVersion: ECMA_VERSION,
1786-
sourceType: "module",
1787-
plugins: {
1788-
dynamicImport: true
1789-
},
1760+
} else {
1761+
comments = [];
1762+
ast = Parser.parse(source, {
1763+
sourceType: this.sourceType,
17901764
onComment: comments
17911765
});
17921766
}
1793-
if(!ast || typeof ast !== "object")
1794-
throw new Error("Source couldn't be parsed");
1767+
17951768
const oldScope = this.scope;
17961769
const oldState = this.state;
17971770
const oldComments = this.comments;
@@ -1817,17 +1790,10 @@ class Parser extends Tapable {
18171790
}
18181791

18191792
evaluate(source) {
1820-
const ast = acorn.parse("(" + source + ")", {
1821-
ranges: true,
1822-
locations: true,
1823-
ecmaVersion: ECMA_VERSION,
1824-
sourceType: "module",
1825-
plugins: {
1826-
dynamicImport: true
1827-
}
1793+
const ast = Parser.parse("(" + source + ")", {
1794+
sourceType: this.sourceType,
1795+
locations: false,
18281796
});
1829-
if(!ast || typeof ast !== "object" || ast.type !== "Program")
1830-
throw new Error("evaluate: Source couldn't be parsed");
18311797
if(ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement")
18321798
throw new Error("evaluate: Source is not a expression");
18331799
return this.evaluateExpression(ast.body[0].expression);
@@ -1885,8 +1851,41 @@ class Parser extends Tapable {
18851851
};
18861852
}
18871853

1888-
}
1854+
static parse(code, options) {
1855+
const type = options.sourceType;
1856+
const parserOptions = Object.assign(Object.create(null), defaultParserOptions, options);
18891857

1890-
Parser.ECMA_VERSION = ECMA_VERSION;
1858+
if(type === "auto") {
1859+
parserOptions.sourceType = "module";
1860+
}
1861+
1862+
let ast;
1863+
let error;
1864+
let threw = false;
1865+
try {
1866+
ast = acorn.parse(code, parserOptions);
1867+
} catch(e) {
1868+
error = e;
1869+
threw = true;
1870+
}
1871+
1872+
if(threw && type === "auto") {
1873+
parserOptions.sourceType = "script";
1874+
if(Array.isArray(parserOptions.onComment)) {
1875+
parserOptions.onComment.length = 0;
1876+
}
1877+
try {
1878+
ast = acorn.parse(code, parserOptions);
1879+
threw = false;
1880+
} catch(e) {}
1881+
}
1882+
1883+
if(threw) {
1884+
throw error;
1885+
}
1886+
1887+
return ast;
1888+
}
1889+
}
18911890

18921891
module.exports = Parser;

lib/optimize/ConcatenatedModule.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
const Module = require("../Module");
88
const Template = require("../Template");
99
const Parser = require("../Parser");
10-
const acorn = require("acorn");
1110
const eslintScope = require("eslint-scope");
1211
const ReplaceSource = require("webpack-sources").ReplaceSource;
1312
const ConcatSource = require("webpack-sources").ConcatSource;
@@ -483,11 +482,8 @@ class ConcatenatedModule extends Module {
483482
const code = source.source();
484483
let ast;
485484
try {
486-
ast = acorn.parse(code, {
487-
ranges: true,
488-
locations: true,
489-
ecmaVersion: Parser.ECMA_VERSION,
490-
sourceType: "module"
485+
ast = Parser.parse(code, {
486+
sourceType: "module",
491487
});
492488
} catch(err) {
493489
if(err.loc && typeof err.loc === "object" && typeof err.loc.line === "number") {

0 commit comments

Comments
 (0)