mirror of https://github.com/webpack/webpack.git
Merge pull request #3297 from Kovensky/template-strings
Implement support for template strings in System.import
This commit is contained in:
commit
0170568b5f
|
|
@ -37,6 +37,9 @@ BasicEvaluatedExpression.prototype.isIdentifier = function() {
|
|||
BasicEvaluatedExpression.prototype.isWrapped = function() {
|
||||
return Object.prototype.hasOwnProperty.call(this, "prefix") || Object.prototype.hasOwnProperty.call(this, "postfix");
|
||||
};
|
||||
BasicEvaluatedExpression.prototype.isTemplateString = function() {
|
||||
return Object.prototype.hasOwnProperty.call(this, "quasis");
|
||||
}
|
||||
BasicEvaluatedExpression.prototype.asBool = function() {
|
||||
if(this.isBoolean()) return this.bool;
|
||||
else if(this.isNull()) return false;
|
||||
|
|
@ -46,6 +49,13 @@ BasicEvaluatedExpression.prototype.asBool = function() {
|
|||
else if(this.isArray()) return true;
|
||||
else if(this.isConstArray()) return true;
|
||||
else if(this.isWrapped()) return this.prefix && this.prefix.asBool() || this.postfix && this.postfix.asBool() ? true : undefined;
|
||||
else if(this.isTemplateString()) {
|
||||
if (this.quasis.length === 1) return this.quasis[0].asBool();
|
||||
for (var i = 0; i < this.quasis.length; i++) {
|
||||
if (this.quasis[i].asBool()) return true;
|
||||
}
|
||||
// can't tell if string will be empty without executing
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
BasicEvaluatedExpression.prototype.set = function(value) {
|
||||
|
|
@ -127,6 +137,13 @@ BasicEvaluatedExpression.prototype.setArray = function(array) {
|
|||
this.array = array;
|
||||
return this;
|
||||
};
|
||||
BasicEvaluatedExpression.prototype.setTemplateString = function(quasis) {
|
||||
if (quasis === null)
|
||||
delete this.quasis;
|
||||
else
|
||||
this.quasis = quasis;
|
||||
return this;
|
||||
}
|
||||
BasicEvaluatedExpression.prototype.addOptions = function(options) {
|
||||
if(!this.options) this.options = [];
|
||||
options.forEach(function(item) {
|
||||
|
|
|
|||
|
|
@ -297,6 +297,45 @@ Parser.prototype.initializeEvaluating = function() {
|
|||
}
|
||||
return new BasicEvaluatedExpression().setString(result).setRange(expr.range);
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Parser} this
|
||||
* @param {"cooked" | "raw"} kind
|
||||
* @param {any[]} quasis
|
||||
* @param {any[]} expressions
|
||||
* @return {BasicEvaluatedExpression[]}
|
||||
*/
|
||||
function getSimplifiedTemplateResult(kind, quasis, expressions) {
|
||||
var i = 0, parts = [];
|
||||
|
||||
for (i = 0; i < quasis.length; i++) {
|
||||
parts.push(new BasicEvaluatedExpression().setString(quasis[i].value[kind]).setRange(quasis[i].range));
|
||||
|
||||
if (i > 0) {
|
||||
var prevExpr = parts[parts.length - 2], lastExpr = parts[parts.length - 1];
|
||||
var expr = this.evaluateExpression(expressions[i-1]);
|
||||
if (!(expr.isString() || expr.isNumber())) continue;
|
||||
|
||||
prevExpr.setString(prevExpr.string + (expr.isString() ? expr.string : expr.number) + lastExpr.string)
|
||||
prevExpr.setRange([prevExpr.range[0], lastExpr.range[1]]);
|
||||
parts.pop();
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
this.plugin("evaluate TemplateLiteral", function(node) {
|
||||
var parts = getSimplifiedTemplateResult.call(this, 'cooked', node.quasis, node.expressions);
|
||||
if (parts.length == 1) {
|
||||
return parts[0].setRange(node.range);
|
||||
}
|
||||
return new BasicEvaluatedExpression().setTemplateString(parts).setRange(node.range);
|
||||
});
|
||||
this.plugin("evaluate TaggedTemplateExpression", function(node) {
|
||||
if (this.evaluateExpression(node.tag).identifier !== 'String.raw') return;
|
||||
var parts = getSimplifiedTemplateResult.call(this, 'raw', node.quasi.quasis, node.quasi.expressions);
|
||||
return new BasicEvaluatedExpression().setTemplateString(parts).setRange(node.range);
|
||||
});
|
||||
}, this);
|
||||
this.plugin("evaluate CallExpression .split", function(expr, param) {
|
||||
if(!param.isString()) return;
|
||||
|
|
|
|||
|
|
@ -4,23 +4,56 @@
|
|||
*/
|
||||
var ContextDependencyHelpers = exports;
|
||||
|
||||
/**
|
||||
* Escapes regular expression metacharacters
|
||||
* @param {string} str
|
||||
* @return string
|
||||
*/
|
||||
function quotemeta(str) {
|
||||
return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&")
|
||||
}
|
||||
|
||||
ContextDependencyHelpers.create = function(Dep, range, param, expr, options) {
|
||||
var dep;
|
||||
if(param.isWrapped() && (param.prefix && param.prefix.isString() || param.postfix && param.postfix.isString())) {
|
||||
var prefix = param.prefix && param.prefix.isString() ? param.prefix.string : "";
|
||||
var postfix = param.postfix && param.postfix.isString() ? param.postfix.string : "";
|
||||
var prefixRange = param.prefix && param.prefix.isString() ? param.prefix.range : null;
|
||||
var valueRange = [prefixRange ? prefixRange[1] : param.range[0], param.range[1]];
|
||||
var idx = prefix.lastIndexOf("/");
|
||||
var context = ".";
|
||||
var dep, prefix, postfix, prefixRange, valueRange, idx, context, regExp;
|
||||
if(param.isTemplateString()) {
|
||||
prefix = param.quasis[0].string;
|
||||
postfix = param.quasis.length > 1 ? param.quasis[param.quasis.length - 1].string : "";
|
||||
prefixRange = [param.quasis[0].range[0], param.quasis[0].range[1]];
|
||||
valueRange = param.range;
|
||||
idx = prefix.lastIndexOf("/");
|
||||
context = ".";
|
||||
if(idx >= 0) {
|
||||
context = prefix.substr(0, idx);
|
||||
prefix = "." + prefix.substr(idx);
|
||||
}
|
||||
var regExp = new RegExp("^" +
|
||||
prefix.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") +
|
||||
// If there are more than two quasis, maybe the generated RegExp can be more precise?
|
||||
regExp = new RegExp("^" +
|
||||
quotemeta(prefix) +
|
||||
options.wrappedContextRegExp.source +
|
||||
postfix.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$");
|
||||
quotemeta(postfix) + "$");
|
||||
dep = new Dep(context, options.wrappedContextRecursive, regExp, range, valueRange);
|
||||
dep.loc = expr.loc;
|
||||
dep.replaces = [{
|
||||
range: prefixRange,
|
||||
value: prefix
|
||||
}];
|
||||
dep.critical = options.wrappedContextCritical && "a part of the request of a dependency is an expression";
|
||||
return dep;
|
||||
} else if(param.isWrapped() && (param.prefix && param.prefix.isString() || param.postfix && param.postfix.isString())) {
|
||||
prefix = param.prefix && param.prefix.isString() ? param.prefix.string : "";
|
||||
postfix = param.postfix && param.postfix.isString() ? param.postfix.string : "";
|
||||
prefixRange = param.prefix && param.prefix.isString() ? param.prefix.range : null;
|
||||
valueRange = [prefixRange ? prefixRange[1] : param.range[0], param.range[1]];
|
||||
idx = prefix.lastIndexOf("/");
|
||||
context = ".";
|
||||
if(idx >= 0) {
|
||||
context = prefix.substr(0, idx);
|
||||
prefix = "." + prefix.substr(idx);
|
||||
}
|
||||
regExp = new RegExp("^" +
|
||||
quotemeta(prefix) +
|
||||
options.wrappedContextRegExp.source +
|
||||
quotemeta(postfix) + "$");
|
||||
dep = new Dep(context, options.wrappedContextRecursive, regExp, range, valueRange);
|
||||
dep.loc = expr.loc;
|
||||
dep.prepend = param.prefix && param.prefix.isString() ? prefix : null;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@ ContextDependencyTemplateAsId.prototype.apply = function(dep, source, outputOpti
|
|||
if(outputOptions.pathinfo) comment = "/*! " + requestShortener.shorten(dep.request) + " */ ";
|
||||
if(dep.module && dep.module.dependencies && dep.module.dependencies.length > 0) {
|
||||
if(dep.valueRange) {
|
||||
if(Array.isArray(dep.replaces)) {
|
||||
for(var i = 0; i < dep.replaces.length; i++) {
|
||||
var rep = dep.replaces[i];
|
||||
source.replace(rep.range[0], rep.range[1] - 1, rep.value)
|
||||
}
|
||||
}
|
||||
source.replace(dep.valueRange[1], dep.range[1] - 1, ")");
|
||||
source.replace(dep.range[0], dep.valueRange[0] - 1, "__webpack_require__(" + comment + JSON.stringify(dep.module.id) + ").resolve(" + (typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : "") + "");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@ ContextDependencyTemplateAsRequireCall.prototype.apply = function(dep, source, o
|
|||
var isAsync = dep.module && dep.module.async;
|
||||
if(dep.module && (isAsync || containsDeps)) {
|
||||
if(dep.valueRange) {
|
||||
if(Array.isArray(dep.replaces)) {
|
||||
for(var i = 0; i < dep.replaces.length; i++) {
|
||||
var rep = dep.replaces[i];
|
||||
source.replace(rep.range[0], rep.range[1] - 1, rep.value)
|
||||
}
|
||||
}
|
||||
source.replace(dep.valueRange[1], dep.range[1] - 1, ")");
|
||||
source.replace(dep.range[0], dep.valueRange[0] - 1, "__webpack_require__(" + comment + JSON.stringify(dep.module.id) + ")(" + (typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : "") + "");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export default "ok";
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
it("should parse template strings in amd requires", function(done) {
|
||||
var name = "abc";
|
||||
var suffix = "Test";
|
||||
|
||||
var pending = [
|
||||
require([`./abc/abcTest`], test),
|
||||
require([`./abc/${name}Test`], test),
|
||||
require([`./${name}/${name}Test`], test),
|
||||
require([`./abc/${name}${suffix}`], test),
|
||||
require([String.raw`./${name}/${name}${suffix}`], test)
|
||||
].length;
|
||||
|
||||
function test (result) {
|
||||
result.default.should.eql("ok")
|
||||
if (--pending <= 0) {
|
||||
done()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
it("should parse template strings in require.ensure requires", function(done) {
|
||||
var name = "abc";
|
||||
var suffix = "Test";
|
||||
|
||||
require.ensure([], function(require) {
|
||||
var imports = [
|
||||
require(`./abc/${name}Test`),
|
||||
require(`./abc/${name}Test`),
|
||||
require(`./${name}/${name}Test`),
|
||||
require(`./abc/${name}${suffix}`),
|
||||
require(String.raw`./${name}/${name}${suffix}`)
|
||||
];
|
||||
|
||||
for (var i = 0; i < imports.length; i++) {
|
||||
imports[i].default.should.eql("ok");
|
||||
}
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should parse template strings in sync requires", function() {
|
||||
var name = "sync";
|
||||
var suffix = "Test";
|
||||
|
||||
var imports = [
|
||||
require(`./sync/${name}Test`),
|
||||
require(`./sync/${name}${suffix}`),
|
||||
require(String.raw`./sync/${name.slice(0, 1)}y${name.slice(2)}${suffix}`),
|
||||
require(`./sync/sync${"Test"}`),
|
||||
require(String.raw`./sync/${"sync"}Test`)
|
||||
];
|
||||
|
||||
for (var i = 0; i < imports.length; i++) {
|
||||
imports[i].default.should.eql("sync");
|
||||
}
|
||||
})
|
||||
|
||||
it("should parse template strings in require.resolve", function() {
|
||||
var name = "sync";
|
||||
|
||||
// Arbitrary assertion; can't use .ok() as it could be 0,
|
||||
// can't use typeof as that depends on webpack config.
|
||||
require.resolve(`./sync/${name}Test`).should.not.be.undefined;
|
||||
})
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
var should = require('should')
|
||||
|
||||
it("should parse template strings in System.import", function(done) {
|
||||
var name = "abc".split("");
|
||||
var suffix = "Test";
|
||||
Promise.all([
|
||||
System.import(`./abc/${name[0]}${name[1]}${name[2]}Test`),
|
||||
System.import(String.raw`./${name.join("")}/${name.join("")}Test`),
|
||||
System.import(String.raw`./abc/${name.join("")}${suffix}`)
|
||||
])
|
||||
.then(function (imports) {
|
||||
for (var i = 0; i < imports.length; i++) {
|
||||
imports[i].default.should.eql("ok");
|
||||
}
|
||||
})
|
||||
.then(function () { done(); }, done)
|
||||
});
|
||||
|
||||
require("./cjs")
|
||||
require("./amd")
|
||||
|
|
@ -0,0 +1 @@
|
|||
export default "sync";
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
var supportsTemplateStrings = require("../../../helpers/supportsTemplateStrings");
|
||||
|
||||
module.exports = function(config) {
|
||||
return !config.minimize && supportsTemplateStrings();
|
||||
};
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = function supportsTemplateStrings() {
|
||||
try {
|
||||
var f = eval("(function f() { return String.raw`a\\b`; })");
|
||||
return f() === "a\\b";
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue