source: imaps-frontend/node_modules/webpack/lib/optimize/InnerGraph.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 9.3 KB
RevLine 
[79a0317]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Sergey Melyukov @smelukov
4*/
5
6"use strict";
7
8const { UsageState } = require("../ExportsInfo");
9
10/** @typedef {import("estree").Node} AnyNode */
11/** @typedef {import("../Dependency")} Dependency */
12/** @typedef {import("../Module")} Module */
13/** @typedef {import("../ModuleGraph")} ModuleGraph */
14/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
15/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
16/** @typedef {import("../Parser").ParserState} ParserState */
17/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
18/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
19
20/** @typedef {Map<TopLevelSymbol | null, Set<string | TopLevelSymbol> | true | undefined>} InnerGraph */
21/** @typedef {function(boolean | Set<string> | undefined): void} UsageCallback */
22
23/**
24 * @typedef {object} StateObject
25 * @property {InnerGraph} innerGraph
26 * @property {TopLevelSymbol=} currentTopLevelSymbol
27 * @property {Map<TopLevelSymbol, Set<UsageCallback>>} usageCallbackMap
28 */
29
30/** @typedef {false|StateObject} State */
31
32/** @type {WeakMap<ParserState, State>} */
33const parserStateMap = new WeakMap();
34const topLevelSymbolTag = Symbol("top level symbol");
35
36/**
37 * @param {ParserState} parserState parser state
38 * @returns {State | undefined} state
39 */
40function getState(parserState) {
41 return parserStateMap.get(parserState);
42}
43
44/**
45 * @param {ParserState} parserState parser state
46 * @returns {void}
47 */
48module.exports.bailout = parserState => {
49 parserStateMap.set(parserState, false);
50};
51
52/**
53 * @param {ParserState} parserState parser state
54 * @returns {void}
55 */
56module.exports.enable = parserState => {
57 const state = parserStateMap.get(parserState);
58 if (state === false) {
59 return;
60 }
61 parserStateMap.set(parserState, {
62 innerGraph: new Map(),
63 currentTopLevelSymbol: undefined,
64 usageCallbackMap: new Map()
65 });
66};
67
68/**
69 * @param {ParserState} parserState parser state
70 * @returns {boolean} true, when enabled
71 */
72module.exports.isEnabled = parserState => {
73 const state = parserStateMap.get(parserState);
74 return Boolean(state);
75};
76
77/**
78 * @param {ParserState} state parser state
79 * @param {TopLevelSymbol | null} symbol the symbol, or null for all symbols
80 * @param {string | TopLevelSymbol | true} usage usage data
81 * @returns {void}
82 */
83module.exports.addUsage = (state, symbol, usage) => {
84 const innerGraphState = getState(state);
85
86 if (innerGraphState) {
87 const { innerGraph } = innerGraphState;
88 const info = innerGraph.get(symbol);
89 if (usage === true) {
90 innerGraph.set(symbol, true);
91 } else if (info === undefined) {
92 innerGraph.set(symbol, new Set([usage]));
93 } else if (info !== true) {
94 info.add(usage);
95 }
96 }
97};
98
99/**
100 * @param {JavascriptParser} parser the parser
101 * @param {string} name name of variable
102 * @param {string | TopLevelSymbol | true} usage usage data
103 * @returns {void}
104 */
105module.exports.addVariableUsage = (parser, name, usage) => {
106 const symbol =
107 /** @type {TopLevelSymbol} */ (
108 parser.getTagData(name, topLevelSymbolTag)
109 ) || module.exports.tagTopLevelSymbol(parser, name);
110 if (symbol) {
111 module.exports.addUsage(parser.state, symbol, usage);
112 }
113};
114
115/**
116 * @param {ParserState} state parser state
117 * @returns {void}
118 */
119module.exports.inferDependencyUsage = state => {
120 const innerGraphState = getState(state);
121
122 if (!innerGraphState) {
123 return;
124 }
125
126 const { innerGraph, usageCallbackMap } = innerGraphState;
127 const processed = new Map();
128 // flatten graph to terminal nodes (string, undefined or true)
129 const nonTerminal = new Set(innerGraph.keys());
130 while (nonTerminal.size > 0) {
131 for (const key of nonTerminal) {
132 /** @type {Set<string|TopLevelSymbol> | true} */
133 let newSet = new Set();
134 let isTerminal = true;
135 const value = innerGraph.get(key);
136 let alreadyProcessed = processed.get(key);
137 if (alreadyProcessed === undefined) {
138 alreadyProcessed = new Set();
139 processed.set(key, alreadyProcessed);
140 }
141 if (value !== true && value !== undefined) {
142 for (const item of value) {
143 alreadyProcessed.add(item);
144 }
145 for (const item of value) {
146 if (typeof item === "string") {
147 newSet.add(item);
148 } else {
149 const itemValue = innerGraph.get(item);
150 if (itemValue === true) {
151 newSet = true;
152 break;
153 }
154 if (itemValue !== undefined) {
155 for (const i of itemValue) {
156 if (i === key) continue;
157 if (alreadyProcessed.has(i)) continue;
158 newSet.add(i);
159 if (typeof i !== "string") {
160 isTerminal = false;
161 }
162 }
163 }
164 }
165 }
166 if (newSet === true) {
167 innerGraph.set(key, true);
168 } else if (newSet.size === 0) {
169 innerGraph.set(key, undefined);
170 } else {
171 innerGraph.set(key, newSet);
172 }
173 }
174 if (isTerminal) {
175 nonTerminal.delete(key);
176
177 // For the global key, merge with all other keys
178 if (key === null) {
179 const globalValue = innerGraph.get(null);
180 if (globalValue) {
181 for (const [key, value] of innerGraph) {
182 if (key !== null && value !== true) {
183 if (globalValue === true) {
184 innerGraph.set(key, true);
185 } else {
186 const newSet = new Set(value);
187 for (const item of globalValue) {
188 newSet.add(item);
189 }
190 innerGraph.set(key, newSet);
191 }
192 }
193 }
194 }
195 }
196 }
197 }
198 }
199
200 /** @type {Map<Dependency, true | Set<string>>} */
201 for (const [symbol, callbacks] of usageCallbackMap) {
202 const usage = /** @type {true | Set<string> | undefined} */ (
203 innerGraph.get(symbol)
204 );
205 for (const callback of callbacks) {
206 callback(usage === undefined ? false : usage);
207 }
208 }
209};
210
211/**
212 * @param {ParserState} state parser state
213 * @param {UsageCallback} onUsageCallback on usage callback
214 */
215module.exports.onUsage = (state, onUsageCallback) => {
216 const innerGraphState = getState(state);
217
218 if (innerGraphState) {
219 const { usageCallbackMap, currentTopLevelSymbol } = innerGraphState;
220 if (currentTopLevelSymbol) {
221 let callbacks = usageCallbackMap.get(currentTopLevelSymbol);
222
223 if (callbacks === undefined) {
224 callbacks = new Set();
225 usageCallbackMap.set(currentTopLevelSymbol, callbacks);
226 }
227
228 callbacks.add(onUsageCallback);
229 } else {
230 onUsageCallback(true);
231 }
232 } else {
233 onUsageCallback(undefined);
234 }
235};
236
237/**
238 * @param {ParserState} state parser state
239 * @param {TopLevelSymbol | undefined} symbol the symbol
240 */
241module.exports.setTopLevelSymbol = (state, symbol) => {
242 const innerGraphState = getState(state);
243
244 if (innerGraphState) {
245 innerGraphState.currentTopLevelSymbol = symbol;
246 }
247};
248
249/**
250 * @param {ParserState} state parser state
251 * @returns {TopLevelSymbol|void} usage data
252 */
253module.exports.getTopLevelSymbol = state => {
254 const innerGraphState = getState(state);
255
256 if (innerGraphState) {
257 return innerGraphState.currentTopLevelSymbol;
258 }
259};
260
261/**
262 * @param {JavascriptParser} parser parser
263 * @param {string} name name of variable
264 * @returns {TopLevelSymbol | undefined} symbol
265 */
266module.exports.tagTopLevelSymbol = (parser, name) => {
267 const innerGraphState = getState(parser.state);
268 if (!innerGraphState) return;
269
270 parser.defineVariable(name);
271
272 const existingTag = /** @type {TopLevelSymbol} */ (
273 parser.getTagData(name, topLevelSymbolTag)
274 );
275 if (existingTag) {
276 return existingTag;
277 }
278
279 const fn = new TopLevelSymbol(name);
280 parser.tagVariable(name, topLevelSymbolTag, fn);
281 return fn;
282};
283
284/**
285 * @param {Dependency} dependency the dependency
286 * @param {Set<string> | boolean} usedByExports usedByExports info
287 * @param {ModuleGraph} moduleGraph moduleGraph
288 * @param {RuntimeSpec} runtime runtime
289 * @returns {boolean} false, when unused. Otherwise true
290 */
291module.exports.isDependencyUsedByExports = (
292 dependency,
293 usedByExports,
294 moduleGraph,
295 runtime
296) => {
297 if (usedByExports === false) return false;
298 if (usedByExports !== true && usedByExports !== undefined) {
299 const selfModule =
300 /** @type {Module} */
301 (moduleGraph.getParentModule(dependency));
302 const exportsInfo = moduleGraph.getExportsInfo(selfModule);
303 let used = false;
304 for (const exportName of usedByExports) {
305 if (exportsInfo.getUsed(exportName, runtime) !== UsageState.Unused)
306 used = true;
307 }
308 if (!used) return false;
309 }
310 return true;
311};
312
313/**
314 * @param {Dependency} dependency the dependency
315 * @param {Set<string> | boolean | undefined} usedByExports usedByExports info
316 * @param {ModuleGraph} moduleGraph moduleGraph
317 * @returns {null | false | function(ModuleGraphConnection, RuntimeSpec): ConnectionState} function to determine if the connection is active
318 */
319module.exports.getDependencyUsedByExportsCondition = (
320 dependency,
321 usedByExports,
322 moduleGraph
323) => {
324 if (usedByExports === false) return false;
325 if (usedByExports !== true && usedByExports !== undefined) {
326 const selfModule =
327 /** @type {Module} */
328 (moduleGraph.getParentModule(dependency));
329 const exportsInfo = moduleGraph.getExportsInfo(selfModule);
330 return (connections, runtime) => {
331 for (const exportName of usedByExports) {
332 if (exportsInfo.getUsed(exportName, runtime) !== UsageState.Unused)
333 return true;
334 }
335 return false;
336 };
337 }
338 return null;
339};
340
341class TopLevelSymbol {
342 /**
343 * @param {string} name name of the variable
344 */
345 constructor(name) {
346 this.name = name;
347 }
348}
349
350module.exports.TopLevelSymbol = TopLevelSymbol;
351module.exports.topLevelSymbolTag = topLevelSymbolTag;
Note: See TracBrowser for help on using the repository browser.