source: frontend/node_modules/webpack/lib/dependencies/HarmonyImportSpecifierDependency.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 16.1 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 Dependency = require("../Dependency");
9const InitFragment = require("../InitFragment");
10const Template = require("../Template");
11const {
12 getDependencyUsedByExportsCondition
13} = require("../optimize/InnerGraph");
14const { getTrimmedIdsAndRange } = require("../util/chainedImports");
15const makeSerializable = require("../util/makeSerializable");
16const { propertyAccess } = require("../util/property");
17const traverseDestructuringAssignmentProperties = require("../util/traverseDestructuringAssignmentProperties");
18const HarmonyImportDependency = require("./HarmonyImportDependency");
19const { ImportPhaseUtils } = require("./ImportPhase");
20
21/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
22/** @typedef {import("../Dependency").GetConditionFn} GetConditionFn */
23/** @typedef {import("../Dependency").RawReferencedExports} RawReferencedExports */
24/** @typedef {import("../Dependency").ReferencedExports} ReferencedExports */
25/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
26/** @typedef {import("../Module")} Module */
27/** @typedef {import("../Module").BuildMeta} BuildMeta */
28/** @typedef {import("../ModuleGraph")} ModuleGraph */
29/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
30/** @typedef {import("../errors/WebpackError")} WebpackError */
31/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperties} DestructuringAssignmentProperties */
32/** @typedef {import("../javascript/JavascriptParser").ImportAttributes} ImportAttributes */
33/** @typedef {import("../javascript/JavascriptParser").Range} Range */
34/** @typedef {import("../optimize/InnerGraph").UsedByExports} UsedByExports */
35/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
36/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
37/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
38/** @typedef {import("../util/chainedImports").IdRanges} IdRanges */
39/** @typedef {import("./HarmonyImportDependency").ExportPresenceMode} ExportPresenceMode */
40/** @typedef {HarmonyImportDependency.Ids} Ids */
41/** @typedef {import("./ImportPhase").ImportPhaseType} ImportPhaseType */
42
43const idsSymbol = /** @type {symbol} */ (
44 Symbol("HarmonyImportSpecifierDependency.ids")
45);
46
47const { ExportPresenceModes } = HarmonyImportDependency;
48
49class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
50 /**
51 * Creates an instance of HarmonyImportSpecifierDependency.
52 * @param {string} request request
53 * @param {number} sourceOrder source order
54 * @param {Ids} ids ids
55 * @param {string} name name
56 * @param {Range} range range
57 * @param {ExportPresenceMode} exportPresenceMode export presence mode
58 * @param {ImportPhaseType} phase import phase
59 * @param {ImportAttributes | undefined} attributes import attributes
60 * @param {IdRanges | undefined} idRanges ranges for members of ids; the two arrays are right-aligned
61 */
62 constructor(
63 request,
64 sourceOrder,
65 ids,
66 name,
67 range,
68 exportPresenceMode,
69 phase,
70 attributes,
71 idRanges // TODO webpack 6 make this non-optional. It must always be set to properly trim ids.
72 ) {
73 super(request, sourceOrder, phase, attributes);
74 this.ids = ids;
75 this.name = name;
76 this.range = range;
77 this.idRanges = idRanges;
78 this.exportPresenceMode = exportPresenceMode;
79 /** @type {undefined | boolean} */
80 this.namespaceObjectAsContext = false;
81 /** @type {undefined | boolean} */
82 this.call = undefined;
83 /** @type {undefined | boolean} */
84 this.directImport = undefined;
85 /** @type {undefined | boolean | string} */
86 this.shorthand = undefined;
87 /** @type {undefined | boolean} */
88 this.asiSafe = undefined;
89 /** @type {UsedByExports | undefined} */
90 this.usedByExports = undefined;
91 /** @type {DestructuringAssignmentProperties | undefined} */
92 this.referencedPropertiesInDestructuring = undefined;
93 }
94
95 // TODO webpack 6 remove
96 /**
97 * Returns id.
98 * @deprecated
99 */
100 get id() {
101 throw new Error("id was renamed to ids and type changed to string[]");
102 }
103
104 // TODO webpack 6 remove
105 /**
106 * Returns id.
107 * @deprecated
108 */
109 getId() {
110 throw new Error("id was renamed to ids and type changed to string[]");
111 }
112
113 // TODO webpack 6 remove
114 /**
115 * Updates id.
116 * @deprecated
117 */
118 setId() {
119 throw new Error("id was renamed to ids and type changed to string[]");
120 }
121
122 get type() {
123 return "harmony import specifier";
124 }
125
126 /**
127 * Returns the imported ids.
128 * @param {ModuleGraph} moduleGraph the module graph
129 * @returns {Ids} the imported ids
130 */
131 getIds(moduleGraph) {
132 const meta = moduleGraph.getMetaIfExisting(this);
133 if (meta === undefined) return this.ids;
134 const ids = meta[idsSymbol];
135 return ids !== undefined ? ids : this.ids;
136 }
137
138 /**
139 * Updates ids using the provided module graph.
140 * @param {ModuleGraph} moduleGraph the module graph
141 * @param {Ids} ids the imported ids
142 * @returns {void}
143 */
144 setIds(moduleGraph, ids) {
145 moduleGraph.getMeta(this)[idsSymbol] = ids;
146 }
147
148 /**
149 * Returns function to determine if the connection is active.
150 * @param {ModuleGraph} moduleGraph module graph
151 * @returns {null | false | GetConditionFn} function to determine if the connection is active
152 */
153 getCondition(moduleGraph) {
154 return getDependencyUsedByExportsCondition(
155 this,
156 this.usedByExports,
157 moduleGraph
158 );
159 }
160
161 /**
162 * Gets module evaluation side effects state.
163 * @param {ModuleGraph} moduleGraph the module graph
164 * @returns {ConnectionState} how this dependency connects the module to referencing modules
165 */
166 getModuleEvaluationSideEffectsState(moduleGraph) {
167 return false;
168 }
169
170 /**
171 * Returns list of exports referenced by this dependency
172 * @param {ModuleGraph} moduleGraph module graph
173 * @param {RuntimeSpec} runtime the runtime for which the module is analysed
174 * @returns {ReferencedExports} referenced exports
175 */
176 getReferencedExports(moduleGraph, runtime) {
177 let ids = this.getIds(moduleGraph);
178 if (ids.length === 0) return this._getReferencedExportsInDestructuring();
179 let namespaceObjectAsContext = this.namespaceObjectAsContext;
180 if (ids[0] === "default") {
181 const selfModule =
182 /** @type {Module} */
183 (moduleGraph.getParentModule(this));
184 const importedModule =
185 /** @type {Module} */
186 (moduleGraph.getModule(this));
187 switch (
188 importedModule.getExportsType(
189 moduleGraph,
190 /** @type {BuildMeta} */
191 (selfModule.buildMeta).strictHarmonyModule
192 )
193 ) {
194 case "default-only":
195 case "default-with-named":
196 if (ids.length === 1) {
197 return this._getReferencedExportsInDestructuring();
198 }
199 ids = ids.slice(1);
200 namespaceObjectAsContext = true;
201 break;
202 case "dynamic":
203 return Dependency.EXPORTS_OBJECT_REFERENCED;
204 }
205 }
206
207 if (
208 this.call &&
209 !this.directImport &&
210 (namespaceObjectAsContext || ids.length > 1)
211 ) {
212 if (ids.length === 1) return Dependency.EXPORTS_OBJECT_REFERENCED;
213 ids = ids.slice(0, -1);
214 }
215
216 return this._getReferencedExportsInDestructuring(ids);
217 }
218
219 /**
220 * Get referenced exports in destructuring.
221 * @param {Ids=} ids ids
222 * @returns {RawReferencedExports} referenced exports
223 */
224 _getReferencedExportsInDestructuring(ids) {
225 if (this.referencedPropertiesInDestructuring) {
226 /** @type {RawReferencedExports} */
227 const refsInDestructuring = [];
228 traverseDestructuringAssignmentProperties(
229 this.referencedPropertiesInDestructuring,
230 (stack) => refsInDestructuring.push(stack.map((p) => p.id))
231 );
232 /** @type {RawReferencedExports} */
233 const refs = [];
234 for (const idsInDestructuring of refsInDestructuring) {
235 refs.push(ids ? [...ids, ...idsInDestructuring] : idsInDestructuring);
236 }
237 return refs;
238 }
239 return ids ? [ids] : Dependency.EXPORTS_OBJECT_REFERENCED;
240 }
241
242 /**
243 * Get effective export presence level.
244 * @param {ModuleGraph} moduleGraph module graph
245 * @returns {ExportPresenceMode} effective mode
246 */
247 _getEffectiveExportPresenceLevel(moduleGraph) {
248 if (this.exportPresenceMode !== ExportPresenceModes.AUTO) {
249 return this.exportPresenceMode;
250 }
251 const buildMeta =
252 /** @type {BuildMeta} */
253 (
254 /** @type {Module} */
255 (moduleGraph.getParentModule(this)).buildMeta
256 );
257 return buildMeta.strictHarmonyModule
258 ? ExportPresenceModes.ERROR
259 : ExportPresenceModes.WARN;
260 }
261
262 /**
263 * Returns warnings.
264 * @param {ModuleGraph} moduleGraph module graph
265 * @returns {WebpackError[] | null | undefined} warnings
266 */
267 getWarnings(moduleGraph) {
268 const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
269 if (exportsPresence === ExportPresenceModes.WARN) {
270 return this._getErrors(moduleGraph);
271 }
272 return null;
273 }
274
275 /**
276 * Returns errors.
277 * @param {ModuleGraph} moduleGraph module graph
278 * @returns {WebpackError[] | null | undefined} errors
279 */
280 getErrors(moduleGraph) {
281 const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
282 if (exportsPresence === ExportPresenceModes.ERROR) {
283 return this._getErrors(moduleGraph);
284 }
285 return null;
286 }
287
288 /**
289 * Returns errors.
290 * @param {ModuleGraph} moduleGraph module graph
291 * @returns {WebpackError[] | undefined} errors
292 */
293 _getErrors(moduleGraph) {
294 const ids = this.getIds(moduleGraph);
295 return this.getLinkingErrors(
296 moduleGraph,
297 ids,
298 `(imported as '${this.name}')`
299 );
300 }
301
302 /**
303 * implement this method to allow the occurrence order plugin to count correctly
304 * @returns {number} count how often the id is used in this dependency
305 */
306 getNumberOfIdOccurrences() {
307 return 0;
308 }
309
310 /**
311 * Serializes this instance into the provided serializer context.
312 * @param {ObjectSerializerContext} context context
313 */
314 serialize(context) {
315 const { write } = context;
316 write(this.ids);
317 write(this.name);
318 write(this.range);
319 write(this.idRanges);
320 write(this.exportPresenceMode);
321 write(this.namespaceObjectAsContext);
322 write(this.call);
323 write(this.directImport);
324 write(this.shorthand);
325 write(this.asiSafe);
326 write(this.usedByExports);
327 write(this.referencedPropertiesInDestructuring);
328 super.serialize(context);
329 }
330
331 /**
332 * Restores this instance from the provided deserializer context.
333 * @param {ObjectDeserializerContext} context context
334 */
335 deserialize(context) {
336 const { read } = context;
337 this.ids = read();
338 this.name = read();
339 this.range = read();
340 this.idRanges = read();
341 this.exportPresenceMode = read();
342 this.namespaceObjectAsContext = read();
343 this.call = read();
344 this.directImport = read();
345 this.shorthand = read();
346 this.asiSafe = read();
347 this.usedByExports = read();
348 this.referencedPropertiesInDestructuring = read();
349 super.deserialize(context);
350 }
351}
352
353makeSerializable(
354 HarmonyImportSpecifierDependency,
355 "webpack/lib/dependencies/HarmonyImportSpecifierDependency"
356);
357
358HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate extends (
359 HarmonyImportDependency.Template
360) {
361 /**
362 * Applies the plugin by registering its hooks on the compiler.
363 * @param {Dependency} dependency the dependency for which the template should be applied
364 * @param {ReplaceSource} source the current replace source which can be modified
365 * @param {DependencyTemplateContext} templateContext the context object
366 * @returns {void}
367 */
368 apply(dependency, source, templateContext) {
369 const dep = /** @type {HarmonyImportSpecifierDependency} */ (dependency);
370 const { moduleGraph, runtime, initFragments } = templateContext;
371 const connection = moduleGraph.getConnection(dep);
372
373 // Only render declaration for import specifier when the dependency is conditional
374 if (connection && !connection.isTargetActive(runtime)) {
375 initFragments.push(
376 new InitFragment(
377 `/* unused harmony import specifier */ var ${dep.name};\n`,
378 InitFragment.STAGE_HARMONY_IMPORTS,
379 0,
380 `unused import specifier ${dep.name}`
381 )
382 );
383
384 return;
385 }
386
387 const ids = dep.getIds(moduleGraph);
388 const {
389 trimmedRange: [trimmedRangeStart, trimmedRangeEnd],
390 trimmedIds
391 } = getTrimmedIdsAndRange(ids, dep.range, dep.idRanges, moduleGraph, dep);
392
393 const exportExpr = this._getCodeForIds(
394 dep,
395 source,
396 templateContext,
397 trimmedIds
398 );
399 if (dep.shorthand) {
400 source.insert(trimmedRangeEnd, `: ${exportExpr}`);
401 } else {
402 source.replace(trimmedRangeStart, trimmedRangeEnd - 1, exportExpr);
403 }
404
405 if (dep.referencedPropertiesInDestructuring) {
406 let prefixedIds = ids;
407
408 if (ids[0] === "default") {
409 const selfModule =
410 /** @type {Module} */
411 (moduleGraph.getParentModule(dep));
412 const importedModule =
413 /** @type {Module} */
414 (moduleGraph.getModule(dep));
415 const exportsType = importedModule.getExportsType(
416 moduleGraph,
417 /** @type {BuildMeta} */
418 (selfModule.buildMeta).strictHarmonyModule
419 );
420 if (
421 (exportsType === "default-only" ||
422 exportsType === "default-with-named") &&
423 ids.length >= 1
424 ) {
425 prefixedIds = ids.slice(1);
426 }
427 }
428
429 /** @type {{ ids: Ids, range: Range, shorthand: boolean | string }[]} */
430 const replacementsInDestructuring = [];
431 traverseDestructuringAssignmentProperties(
432 dep.referencedPropertiesInDestructuring,
433 undefined,
434 (stack) => {
435 const property = stack[stack.length - 1];
436 replacementsInDestructuring.push({
437 ids: stack.map((p) => p.id),
438 range: property.range,
439 shorthand: property.shorthand
440 });
441 }
442 );
443 for (const { ids, shorthand, range } of replacementsInDestructuring) {
444 /** @type {Ids} */
445 const concatedIds = [...prefixedIds, ...ids];
446 const module = /** @type {Module} */ (moduleGraph.getModule(dep));
447 const used = moduleGraph
448 .getExportsInfo(module)
449 .getUsedName(concatedIds, runtime);
450 if (!used) return;
451 const newName = used[used.length - 1];
452 const name = concatedIds[concatedIds.length - 1];
453 if (newName === name) continue;
454
455 const comment = `${Template.toNormalComment(name)} `;
456 const key = comment + JSON.stringify(newName);
457 source.replace(
458 range[0],
459 range[1] - 1,
460 shorthand ? `${key}: ${name}` : `${key}`
461 );
462 }
463 }
464 }
465
466 /**
467 * Returns generated code.
468 * @param {HarmonyImportSpecifierDependency} dep dependency
469 * @param {ReplaceSource} source source
470 * @param {DependencyTemplateContext} templateContext context
471 * @param {Ids} ids ids
472 * @returns {string} generated code
473 */
474 _getCodeForIds(dep, source, templateContext, ids) {
475 const { moduleGraph, module, runtime, concatenationScope } =
476 templateContext;
477 const connection = moduleGraph.getConnection(dep);
478 /** @type {string} */
479 let exportExpr;
480 if (
481 connection &&
482 concatenationScope &&
483 concatenationScope.isModuleInScope(connection.module)
484 ) {
485 if (ids.length === 0) {
486 exportExpr = concatenationScope.createModuleReference(
487 connection.module,
488 {
489 asiSafe: dep.asiSafe,
490 deferredImport: ImportPhaseUtils.isDefer(dep.phase)
491 }
492 );
493 } else if (dep.namespaceObjectAsContext && ids.length === 1) {
494 exportExpr =
495 concatenationScope.createModuleReference(connection.module, {
496 asiSafe: dep.asiSafe,
497 deferredImport: ImportPhaseUtils.isDefer(dep.phase)
498 }) + propertyAccess(ids);
499 } else {
500 exportExpr = concatenationScope.createModuleReference(
501 connection.module,
502 {
503 ids,
504 call: dep.call,
505 directImport: dep.directImport,
506 asiSafe: dep.asiSafe,
507 deferredImport: ImportPhaseUtils.isDefer(dep.phase)
508 }
509 );
510 }
511 } else {
512 super.apply(dep, source, templateContext);
513
514 const { runtimeTemplate, initFragments, runtimeRequirements } =
515 templateContext;
516
517 exportExpr = runtimeTemplate.exportFromImport({
518 moduleGraph,
519 module: /** @type {Module} */ (moduleGraph.getModule(dep)),
520 chunkGraph: templateContext.chunkGraph,
521 request: dep.request,
522 exportName: ids,
523 originModule: module,
524 asiSafe: dep.shorthand ? true : dep.asiSafe,
525 isCall: dep.call,
526 callContext: !dep.directImport,
527 defaultInterop: true,
528 importVar: dep.getImportVar(moduleGraph),
529 initFragments,
530 runtime,
531 runtimeRequirements,
532 dependency: dep
533 });
534 }
535 return exportExpr;
536 }
537};
538
539module.exports = HarmonyImportSpecifierDependency;
540module.exports.idsSymbol = idsSymbol;
Note: See TracBrowser for help on using the repository browser.