source: imaps-frontend/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js

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

F4 Finalna Verzija

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
9const { getImportAttributes } = require("../javascript/JavascriptParser");
10const InnerGraph = require("../optimize/InnerGraph");
11const ConstDependency = require("./ConstDependency");
12const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
13const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency");
14const HarmonyEvaluatedImportSpecifierDependency = require("./HarmonyEvaluatedImportSpecifierDependency");
15const HarmonyExports = require("./HarmonyExports");
16const { ExportPresenceModes } = require("./HarmonyImportDependency");
17const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
18const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
19
20/** @typedef {import("estree").Identifier} Identifier */
21/** @typedef {import("estree").Literal} Literal */
22/** @typedef {import("estree").MemberExpression} MemberExpression */
23/** @typedef {import("estree").ObjectExpression} ObjectExpression */
24/** @typedef {import("estree").Property} Property */
25/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
26/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
27/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
28/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
29/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
30/** @typedef {import("../javascript/JavascriptParser").ExportAllDeclaration} ExportAllDeclaration */
31/** @typedef {import("../javascript/JavascriptParser").ExportNamedDeclaration} ExportNamedDeclaration */
32/** @typedef {import("../javascript/JavascriptParser").ImportAttributes} ImportAttributes */
33/** @typedef {import("../javascript/JavascriptParser").ImportDeclaration} ImportDeclaration */
34/** @typedef {import("../javascript/JavascriptParser").ImportExpression} ImportExpression */
35/** @typedef {import("../javascript/JavascriptParser").Range} Range */
36/** @typedef {import("../optimize/InnerGraph").InnerGraph} InnerGraph */
37/** @typedef {import("../optimize/InnerGraph").TopLevelSymbol} TopLevelSymbol */
38/** @typedef {import("./HarmonyImportDependency")} HarmonyImportDependency */
39
40const harmonySpecifierTag = Symbol("harmony import");
41
42/**
43 * @typedef {object} HarmonySettings
44 * @property {string[]} ids
45 * @property {string} source
46 * @property {number} sourceOrder
47 * @property {string} name
48 * @property {boolean} await
49 * @property {Record<string, any> | undefined} assertions
50 */
51
52module.exports = class HarmonyImportDependencyParserPlugin {
53 /**
54 * @param {JavascriptParserOptions} options options
55 */
56 constructor(options) {
57 this.exportPresenceMode =
58 options.importExportsPresence !== undefined
59 ? ExportPresenceModes.fromUserOption(options.importExportsPresence)
60 : options.exportsPresence !== undefined
61 ? ExportPresenceModes.fromUserOption(options.exportsPresence)
62 : options.strictExportPresence
63 ? ExportPresenceModes.ERROR
64 : ExportPresenceModes.AUTO;
65 this.strictThisContextOnImports = options.strictThisContextOnImports;
66 }
67
68 /**
69 * @param {JavascriptParser} parser the parser
70 * @returns {void}
71 */
72 apply(parser) {
73 const { exportPresenceMode } = this;
74
75 /**
76 * @param {string[]} members members
77 * @param {boolean[]} membersOptionals members Optionals
78 * @returns {string[]} a non optional part
79 */
80 function getNonOptionalPart(members, membersOptionals) {
81 let i = 0;
82 while (i < members.length && membersOptionals[i] === false) i++;
83 return i !== members.length ? members.slice(0, i) : members;
84 }
85
86 /**
87 * @param {TODO} node member expression
88 * @param {number} count count
89 * @returns {TODO} member expression
90 */
91 function getNonOptionalMemberChain(node, count) {
92 while (count--) node = node.object;
93 return node;
94 }
95
96 parser.hooks.isPure
97 .for("Identifier")
98 .tap("HarmonyImportDependencyParserPlugin", expression => {
99 const expr = /** @type {Identifier} */ (expression);
100 if (
101 parser.isVariableDefined(expr.name) ||
102 parser.getTagData(expr.name, harmonySpecifierTag)
103 ) {
104 return true;
105 }
106 });
107 parser.hooks.import.tap(
108 "HarmonyImportDependencyParserPlugin",
109 (statement, source) => {
110 parser.state.lastHarmonyImportOrder =
111 (parser.state.lastHarmonyImportOrder || 0) + 1;
112 const clearDep = new ConstDependency(
113 parser.isAsiPosition(/** @type {Range} */ (statement.range)[0])
114 ? ";"
115 : "",
116 /** @type {Range} */ (statement.range)
117 );
118 clearDep.loc = /** @type {DependencyLocation} */ (statement.loc);
119 parser.state.module.addPresentationalDependency(clearDep);
120 parser.unsetAsiPosition(/** @type {Range} */ (statement.range)[1]);
121 const attributes = getImportAttributes(statement);
122 const sideEffectDep = new HarmonyImportSideEffectDependency(
123 /** @type {string} */ (source),
124 parser.state.lastHarmonyImportOrder,
125 attributes
126 );
127 sideEffectDep.loc = /** @type {DependencyLocation} */ (statement.loc);
128 parser.state.module.addDependency(sideEffectDep);
129 return true;
130 }
131 );
132 parser.hooks.importSpecifier.tap(
133 "HarmonyImportDependencyParserPlugin",
134 (statement, source, id, name) => {
135 const ids = id === null ? [] : [id];
136 parser.tagVariable(name, harmonySpecifierTag, {
137 name,
138 source,
139 ids,
140 sourceOrder: parser.state.lastHarmonyImportOrder,
141 assertions: getImportAttributes(statement)
142 });
143 return true;
144 }
145 );
146 parser.hooks.binaryExpression.tap(
147 "HarmonyImportDependencyParserPlugin",
148 expression => {
149 if (expression.operator !== "in") return;
150
151 const leftPartEvaluated = parser.evaluateExpression(expression.left);
152 if (leftPartEvaluated.couldHaveSideEffects()) return;
153 const leftPart = leftPartEvaluated.asString();
154 if (!leftPart) return;
155
156 const rightPart = parser.evaluateExpression(expression.right);
157 if (!rightPart.isIdentifier()) return;
158
159 const rootInfo = rightPart.rootInfo;
160 if (
161 typeof rootInfo === "string" ||
162 !rootInfo ||
163 !rootInfo.tagInfo ||
164 rootInfo.tagInfo.tag !== harmonySpecifierTag
165 )
166 return;
167 const settings = rootInfo.tagInfo.data;
168 const members =
169 /** @type {(() => string[])} */
170 (rightPart.getMembers)();
171 const dep = new HarmonyEvaluatedImportSpecifierDependency(
172 settings.source,
173 settings.sourceOrder,
174 settings.ids.concat(members).concat([leftPart]),
175 settings.name,
176 /** @type {Range} */ (expression.range),
177 settings.assertions,
178 "in"
179 );
180 dep.directImport = members.length === 0;
181 dep.asiSafe = !parser.isAsiPosition(
182 /** @type {Range} */ (expression.range)[0]
183 );
184 dep.loc = /** @type {DependencyLocation} */ (expression.loc);
185 parser.state.module.addDependency(dep);
186 InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
187 return true;
188 }
189 );
190 parser.hooks.expression
191 .for(harmonySpecifierTag)
192 .tap("HarmonyImportDependencyParserPlugin", expr => {
193 const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
194 const dep = new HarmonyImportSpecifierDependency(
195 settings.source,
196 settings.sourceOrder,
197 settings.ids,
198 settings.name,
199 /** @type {Range} */ (expr.range),
200 exportPresenceMode,
201 settings.assertions,
202 []
203 );
204 dep.referencedPropertiesInDestructuring =
205 parser.destructuringAssignmentPropertiesFor(expr);
206 dep.shorthand = parser.scope.inShorthand;
207 dep.directImport = true;
208 dep.asiSafe = !parser.isAsiPosition(
209 /** @type {Range} */ (expr.range)[0]
210 );
211 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
212 dep.call = parser.scope.inTaggedTemplateTag;
213 parser.state.module.addDependency(dep);
214 InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
215 return true;
216 });
217 parser.hooks.expressionMemberChain
218 .for(harmonySpecifierTag)
219 .tap(
220 "HarmonyImportDependencyParserPlugin",
221 (expression, members, membersOptionals, memberRanges) => {
222 const settings = /** @type {HarmonySettings} */ (
223 parser.currentTagData
224 );
225 const nonOptionalMembers = getNonOptionalPart(
226 members,
227 membersOptionals
228 );
229 /** @type {Range[]} */
230 const ranges = memberRanges.slice(
231 0,
232 memberRanges.length - (members.length - nonOptionalMembers.length)
233 );
234 const expr =
235 nonOptionalMembers !== members
236 ? getNonOptionalMemberChain(
237 expression,
238 members.length - nonOptionalMembers.length
239 )
240 : expression;
241 const ids = settings.ids.concat(nonOptionalMembers);
242 const dep = new HarmonyImportSpecifierDependency(
243 settings.source,
244 settings.sourceOrder,
245 ids,
246 settings.name,
247 /** @type {Range} */ (expr.range),
248 exportPresenceMode,
249 settings.assertions,
250 ranges
251 );
252 dep.referencedPropertiesInDestructuring =
253 parser.destructuringAssignmentPropertiesFor(expr);
254 dep.asiSafe = !parser.isAsiPosition(
255 /** @type {Range} */ (expr.range)[0]
256 );
257 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
258 parser.state.module.addDependency(dep);
259 InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
260 return true;
261 }
262 );
263 parser.hooks.callMemberChain
264 .for(harmonySpecifierTag)
265 .tap(
266 "HarmonyImportDependencyParserPlugin",
267 (expression, members, membersOptionals, memberRanges) => {
268 const { arguments: args, callee } = expression;
269 const settings = /** @type {HarmonySettings} */ (
270 parser.currentTagData
271 );
272 const nonOptionalMembers = getNonOptionalPart(
273 members,
274 membersOptionals
275 );
276 /** @type {Range[]} */
277 const ranges = memberRanges.slice(
278 0,
279 memberRanges.length - (members.length - nonOptionalMembers.length)
280 );
281 const expr =
282 nonOptionalMembers !== members
283 ? getNonOptionalMemberChain(
284 callee,
285 members.length - nonOptionalMembers.length
286 )
287 : callee;
288 const ids = settings.ids.concat(nonOptionalMembers);
289 const dep = new HarmonyImportSpecifierDependency(
290 settings.source,
291 settings.sourceOrder,
292 ids,
293 settings.name,
294 /** @type {Range} */ (expr.range),
295 exportPresenceMode,
296 settings.assertions,
297 ranges
298 );
299 dep.directImport = members.length === 0;
300 dep.call = true;
301 dep.asiSafe = !parser.isAsiPosition(
302 /** @type {Range} */ (expr.range)[0]
303 );
304 // only in case when we strictly follow the spec we need a special case here
305 dep.namespaceObjectAsContext =
306 members.length > 0 &&
307 /** @type {boolean} */ (this.strictThisContextOnImports);
308 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
309 parser.state.module.addDependency(dep);
310 if (args) parser.walkExpressions(args);
311 InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
312 return true;
313 }
314 );
315 const { hotAcceptCallback, hotAcceptWithoutCallback } =
316 HotModuleReplacementPlugin.getParserHooks(parser);
317 hotAcceptCallback.tap(
318 "HarmonyImportDependencyParserPlugin",
319 (expr, requests) => {
320 if (!HarmonyExports.isEnabled(parser.state)) {
321 // This is not a harmony module, skip it
322 return;
323 }
324 const dependencies = requests.map(request => {
325 const dep = new HarmonyAcceptImportDependency(request);
326 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
327 parser.state.module.addDependency(dep);
328 return dep;
329 });
330 if (dependencies.length > 0) {
331 const dep = new HarmonyAcceptDependency(
332 /** @type {Range} */
333 (expr.range),
334 dependencies,
335 true
336 );
337 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
338 parser.state.module.addDependency(dep);
339 }
340 }
341 );
342 hotAcceptWithoutCallback.tap(
343 "HarmonyImportDependencyParserPlugin",
344 (expr, requests) => {
345 if (!HarmonyExports.isEnabled(parser.state)) {
346 // This is not a harmony module, skip it
347 return;
348 }
349 const dependencies = requests.map(request => {
350 const dep = new HarmonyAcceptImportDependency(request);
351 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
352 parser.state.module.addDependency(dep);
353 return dep;
354 });
355 if (dependencies.length > 0) {
356 const dep = new HarmonyAcceptDependency(
357 /** @type {Range} */
358 (expr.range),
359 dependencies,
360 false
361 );
362 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
363 parser.state.module.addDependency(dep);
364 }
365 }
366 );
367 }
368};
369
370module.exports.harmonySpecifierTag = harmonySpecifierTag;
Note: See TracBrowser for help on using the repository browser.