refactor to simpler way of extracting options from comments

This commit is contained in:
Tobias Koppers 2017-04-10 11:35:32 +02:00
parent 83aeea8c46
commit 180f5e541c
5 changed files with 51 additions and 44 deletions

View File

@ -4,11 +4,15 @@
*/
var acorn = require("acorn-dynamic-import").default;
var Tapable = require("tapable");
var json5 = require("json5");
var BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
function Parser(options) {
Tapable.call(this);
this.options = options;
this.scope = undefined;
this.state = undefined;
this.comments = undefined;
this.initializeEvaluating();
}
module.exports = Parser;
@ -1187,16 +1191,19 @@ Parser.prototype.parse = function parse(source, initialState) {
throw new Error("Source couldn't be parsed");
var oldScope = this.scope;
var oldState = this.state;
var oldComments = this.comments;
this.scope = {
inTry: false,
definitions: [],
renames: {}
};
var state = this.state = initialState || {};
this.comments = comments;
if(this.applyPluginsBailResult("program", ast, comments) === undefined)
this.walkStatements(ast.body);
this.scope = oldScope;
this.state = oldState;
this.comments = oldComments;
return state;
};
@ -1216,3 +1223,20 @@ Parser.prototype.evaluate = function evaluate(source) {
throw new Error("evaluate: Source is not a expression");
return this.evaluateExpression(ast.body[0].expression);
};
Parser.prototype.getComments = function getComments(range) {
return this.comments.filter(comment => comment.range[0] >= range[0] && comment.range[1] <= range[1]);
};
Parser.prototype.getCommentOptions = function getCommentOptions(range) {
var comments = this.getComments(range);
if(comments.length === 0) return null;
var options = comments.map(comment => {
try {
return json5.parse(`{${comment.value}}`);
} catch(e) {
return {};
}
});
return options.reduce((o, i) => Object.assign(o, i), {});
};

View File

@ -15,47 +15,21 @@ class ImportParserPlugin {
apply(parser) {
const options = this.options;
let parsedComments, chunkNameAssignment;
parser.plugin("program", (ast, comments) => {
parsedComments = comments;
});
// use /* webpackChunkName = "chunkName" */ to specify a chunkName
parser.plugin("evaluate AssignmentExpression", (assignment) => {
if(assignment.left.name === "webpackChunkName") {
chunkNameAssignment = assignment;
}
});
parser.plugin(["call System.import", "import-call"], (expr) => {
if(expr.arguments.length !== 1)
throw new Error("Incorrect number of arguments provided to 'import(module: string) -> Promise'.");
const param = parser.evaluateExpression(expr.arguments[0]);
const exprEndPos = expr.end;
const paramEndPos = expr.arguments[0].end;
let chunkName = null;
//check chunkName from comments
if(parsedComments.length && exprEndPos - paramEndPos > "/*webpackChunkName=*/".length) {
for(let i = 0; i < parsedComments.length; i++) {
let comment = parsedComments[i];
// should match the location and length
if(comment.type === "Block" && comment.start >= paramEndPos && comment.end < exprEndPos) {
chunkNameAssignment = null;
parser.evaluate(comment.value);
// expect an AssignmentExpression after evaluate
if(chunkNameAssignment) {
const chunkNameExpr = parser.evaluateExpression(chunkNameAssignment.right);
if(chunkNameExpr.isString()) {
chunkName = chunkNameExpr.string;
} else {
throw new Error(`\`webpackChunkName\` expected a String, but received: ${comment.value} .`);
}
}
break;
}
const importOptions = parser.getCommentOptions(expr.range);
if(importOptions) {
if(typeof importOptions.webpackChunkName !== "undefined") {
if(typeof importOptions.webpackChunkName !== "string")
throw new Error(`\`webpackChunkName\` expected a string, but received: ${importOptions.webpackChunkName}.`);
chunkName = importOptions.webpackChunkName;
}
}

View File

@ -12,6 +12,7 @@
"enhanced-resolve": "^3.0.0",
"interpret": "^1.0.0",
"json-loader": "^0.5.4",
"json5": "^0.5.1",
"loader-runner": "^2.3.0",
"loader-utils": "^0.2.16",
"memory-fs": "~0.4.1",

View File

@ -69,18 +69,20 @@ it("should handle empty named chunks when there is an error callback", function(
sync = false;
});
});
it("should be able to use named chunks in import()", function(done) {
var sync = false;
import("./empty?import1-in-chunk1" /* webpackChunkName = "import-named-chunk-1" */).then(function(result){
import("./empty?import2-in-chunk1" /* webpackChunkName = "import-named-chunk-1" */).then(function(result){
import("./empty?import1-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */).then(function(result){
var i = 0;
import("./empty?import2-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */).then(function(result){
sync.should.be.ok();
if(i++ > 0) done();
}).catch(function(err){
done(err);
});
import("./empty?import3-in-chunk2" /* webpackChunkName = "import-named-chunk-2" */).then(function(result){
import("./empty?import3-in-chunk2" /* webpackChunkName: "import-named-chunk-2" */).then(function(result){
sync.should.not.be.ok();
done();
if(i++ > 0) done();
}).catch(function(err){
done(err);
});
@ -94,15 +96,17 @@ it("should be able to use named chunks in import()", function(done) {
it("should be able to use named chunk in context import()", function(done) {
var mpty = "mpty";
var sync = false;
import("./e" + mpty + "2" /* webpackChunkName = "context-named-chunk" */).then(function(result) {
import("./e" + mpty + "3" /* webpackChunkName = "context-named-chunk" */).then(function(result){
import("./e" + mpty + "2" /* webpackChunkName: "context-named-chunk" */).then(function(result) {
var i = 0;
import("./e" + mpty + "3" /* webpackChunkName: "context-named-chunk" */).then(function(result){
sync.should.be.ok();
if(i++ > 0) done();
}).catch(function(err){
done(err);
});
import("./e" + mpty + "4" /* webpackChunkName = "context-named-chunk-2" */).then(function(result){
import("./e" + mpty + "4" /* webpackChunkName: "context-named-chunk-2" */).then(function(result){
sync.should.not.be.ok();
done();
if(i++ > 0) done();
}).catch(function(err){
done(err);
});

View File

@ -47,10 +47,14 @@ acorn@^3.0.4:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
acorn@^4.0.3, acorn@^4.0.4:
acorn@^4.0.3:
version "4.0.11"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
acorn@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
agent-base@2:
version "2.0.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e"
@ -2102,7 +2106,7 @@ json3@3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
json5@^0.5.0:
json5@^0.5.0, json5@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"