Blame view

node_modules/webpack/lib/DefinePlugin.js 4.27 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  /*
  	MIT License http://www.opensource.org/licenses/mit-license.php
  	Author Tobias Koppers @sokra
  */
  "use strict";
  
  const ConstDependency = require("./dependencies/ConstDependency");
  const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
  const ParserHelpers = require("./ParserHelpers");
  const NullFactory = require("./NullFactory");
  
  class DefinePlugin {
  	constructor(definitions) {
  		this.definitions = definitions;
  	}
  
  	apply(compiler) {
  		const definitions = this.definitions;
  		compiler.plugin("compilation", (compilation, params) => {
  			compilation.dependencyFactories.set(ConstDependency, new NullFactory());
  			compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
  
  			params.normalModuleFactory.plugin("parser", (parser) => {
  				(function walkDefinitions(definitions, prefix) {
  					Object.keys(definitions).forEach((key) => {
  						const code = definitions[key];
  						if(code && typeof code === "object" && !(code instanceof RegExp)) {
  							walkDefinitions(code, prefix + key + ".");
  							applyObjectDefine(prefix + key, code);
  							return;
  						}
  						applyDefineKey(prefix, key);
  						applyDefine(prefix + key, code);
  					});
  				}(definitions, ""));
  
  				function stringifyObj(obj) {
  					return "Object({" + Object.keys(obj).map((key) => {
  						const code = obj[key];
  						return JSON.stringify(key) + ":" + toCode(code);
  					}).join(",") + "})";
  				}
  
  				function toCode(code) {
  					if(code === null) return "null";
  					else if(code === undefined) return "undefined";
  					else if(code instanceof RegExp && code.toString) return code.toString();
  					else if(typeof code === "function" && code.toString) return "(" + code.toString() + ")";
  					else if(typeof code === "object") return stringifyObj(code);
  					else return code + "";
  				}
  
  				function applyDefineKey(prefix, key) {
  					const splittedKey = key.split(".");
  					splittedKey.slice(1).forEach((_, i) => {
  						const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
  						parser.plugin("can-rename " + fullKey, ParserHelpers.approve);
  					});
  				}
  
  				function applyDefine(key, code) {
  					const isTypeof = /^typeof\s+/.test(key);
  					if(isTypeof) key = key.replace(/^typeof\s+/, "");
  					let recurse = false;
  					let recurseTypeof = false;
  					code = toCode(code);
  					if(!isTypeof) {
  						parser.plugin("can-rename " + key, ParserHelpers.approve);
  						parser.plugin("evaluate Identifier " + key, (expr) => {
  							/**
  							 * this is needed in case there is a recursion in the DefinePlugin
  							 * to prevent an endless recursion
  							 * e.g.: new DefinePlugin({
  							 * "a": "b",
  							 * "b": "a"
  							 * });
  							 */
  							if(recurse) return;
  							recurse = true;
  							const res = parser.evaluate(code);
  							recurse = false;
  							res.setRange(expr.range);
  							return res;
  						});
  						parser.plugin("expression " + key, ParserHelpers.toConstantDependency(code));
  					}
  					const typeofCode = isTypeof ? code : "typeof (" + code + ")";
  					parser.plugin("evaluate typeof " + key, (expr) => {
  						/**
  						 * this is needed in case there is a recursion in the DefinePlugin
  						 * to prevent an endless recursion
  						 * e.g.: new DefinePlugin({
  						 * "typeof a": "tyepof b",
  						 * "typeof b": "typeof a"
  						 * });
  						 */
  						if(recurseTypeof) return;
  						recurseTypeof = true;
  						const res = parser.evaluate(typeofCode);
  						recurseTypeof = false;
  						res.setRange(expr.range);
  						return res;
  					});
  					parser.plugin("typeof " + key, (expr) => {
  						const res = parser.evaluate(typeofCode);
  						if(!res.isString()) return;
  						return ParserHelpers.toConstantDependency(JSON.stringify(res.string)).bind(parser)(expr);
  					});
  				}
  
  				function applyObjectDefine(key, obj) {
  					const code = stringifyObj(obj);
  					parser.plugin("can-rename " + key, ParserHelpers.approve);
  					parser.plugin("evaluate Identifier " + key, (expr) => new BasicEvaluatedExpression().setTruthy().setRange(expr.range));
  					parser.plugin("evaluate typeof " + key, ParserHelpers.evaluateToString("object"));
  					parser.plugin("expression " + key, ParserHelpers.toConstantDependency(code));
  					parser.plugin("typeof " + key, ParserHelpers.toConstantDependency(JSON.stringify("object")));
  				}
  			});
  		});
  	}
  }
  module.exports = DefinePlugin;