source: imaps-frontend/node_modules/webpack/lib/library/AssignLibraryPlugin.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.1 KB
RevLine 
[79a0317]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { ConcatSource } = require("webpack-sources");
9const { UsageState } = require("../ExportsInfo");
10const RuntimeGlobals = require("../RuntimeGlobals");
11const Template = require("../Template");
12const propertyAccess = require("../util/propertyAccess");
13const { getEntryRuntime } = require("../util/runtime");
14const AbstractLibraryPlugin = require("./AbstractLibraryPlugin");
15
16/** @typedef {import("webpack-sources").Source} Source */
17/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
18/** @typedef {import("../../declarations/WebpackOptions").LibraryType} LibraryType */
19/** @typedef {import("../Chunk")} Chunk */
20/** @typedef {import("../Compilation")} Compilation */
21/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
22/** @typedef {import("../Compiler")} Compiler */
23/** @typedef {import("../Module")} Module */
24/** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */
25/** @typedef {import("../javascript/JavascriptModulesPlugin").StartupRenderContext} StartupRenderContext */
26/** @typedef {import("../util/Hash")} Hash */
27/** @template T @typedef {import("./AbstractLibraryPlugin").LibraryContext<T>} LibraryContext<T> */
28
29const KEYWORD_REGEX =
30 /^(await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|super|switch|static|this|throw|try|true|typeof|var|void|while|with|yield)$/;
31const IDENTIFIER_REGEX =
32 /^[\p{L}\p{Nl}$_][\p{L}\p{Nl}$\p{Mn}\p{Mc}\p{Nd}\p{Pc}]*$/iu;
33
34/**
35 * Validates the library name by checking for keywords and valid characters
36 * @param {string} name name to be validated
37 * @returns {boolean} true, when valid
38 */
39const isNameValid = name =>
40 !KEYWORD_REGEX.test(name) && IDENTIFIER_REGEX.test(name);
41
42/**
43 * @param {string[]} accessor variable plus properties
44 * @param {number} existingLength items of accessor that are existing already
45 * @param {boolean=} initLast if the last property should also be initialized to an object
46 * @returns {string} code to access the accessor while initializing
47 */
48const accessWithInit = (accessor, existingLength, initLast = false) => {
49 // This generates for [a, b, c, d]:
50 // (((a = typeof a === "undefined" ? {} : a).b = a.b || {}).c = a.b.c || {}).d
51 const base = accessor[0];
52 if (accessor.length === 1 && !initLast) return base;
53 let current =
54 existingLength > 0
55 ? base
56 : `(${base} = typeof ${base} === "undefined" ? {} : ${base})`;
57
58 // i is the current position in accessor that has been printed
59 let i = 1;
60
61 // all properties printed so far (excluding base)
62 /** @type {string[] | undefined} */
63 let propsSoFar;
64
65 // if there is existingLength, print all properties until this position as property access
66 if (existingLength > i) {
67 propsSoFar = accessor.slice(1, existingLength);
68 i = existingLength;
69 current += propertyAccess(propsSoFar);
70 } else {
71 propsSoFar = [];
72 }
73
74 // all remaining properties (except the last one when initLast is not set)
75 // should be printed as initializer
76 const initUntil = initLast ? accessor.length : accessor.length - 1;
77 for (; i < initUntil; i++) {
78 const prop = accessor[i];
79 propsSoFar.push(prop);
80 current = `(${current}${propertyAccess([prop])} = ${base}${propertyAccess(
81 propsSoFar
82 )} || {})`;
83 }
84
85 // print the last property as property access if not yet printed
86 if (i < accessor.length)
87 current = `${current}${propertyAccess([accessor[accessor.length - 1]])}`;
88
89 return current;
90};
91
92/**
93 * @typedef {object} AssignLibraryPluginOptions
94 * @property {LibraryType} type
95 * @property {string[] | "global"} prefix name prefix
96 * @property {string | false} declare declare name as variable
97 * @property {"error"|"static"|"copy"|"assign"} unnamed behavior for unnamed library name
98 * @property {"copy"|"assign"=} named behavior for named library name
99 */
100
101/**
102 * @typedef {object} AssignLibraryPluginParsed
103 * @property {string | string[]} name
104 * @property {string | string[] | undefined} export
105 */
106
107/**
108 * @typedef {AssignLibraryPluginParsed} T
109 * @extends {AbstractLibraryPlugin<AssignLibraryPluginParsed>}
110 */
111class AssignLibraryPlugin extends AbstractLibraryPlugin {
112 /**
113 * @param {AssignLibraryPluginOptions} options the plugin options
114 */
115 constructor(options) {
116 super({
117 pluginName: "AssignLibraryPlugin",
118 type: options.type
119 });
120 this.prefix = options.prefix;
121 this.declare = options.declare;
122 this.unnamed = options.unnamed;
123 this.named = options.named || "assign";
124 }
125
126 /**
127 * @param {LibraryOptions} library normalized library option
128 * @returns {T | false} preprocess as needed by overriding
129 */
130 parseOptions(library) {
131 const { name } = library;
132 if (this.unnamed === "error") {
133 if (typeof name !== "string" && !Array.isArray(name)) {
134 throw new Error(
135 `Library name must be a string or string array. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}`
136 );
137 }
138 } else if (name && typeof name !== "string" && !Array.isArray(name)) {
139 throw new Error(
140 `Library name must be a string, string array or unset. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}`
141 );
142 }
143 const _name = /** @type {string | string[]} */ (name);
144 return {
145 name: _name,
146 export: library.export
147 };
148 }
149
150 /**
151 * @param {Module} module the exporting entry module
152 * @param {string} entryName the name of the entrypoint
153 * @param {LibraryContext<T>} libraryContext context
154 * @returns {void}
155 */
156 finishEntryModule(
157 module,
158 entryName,
159 { options, compilation, compilation: { moduleGraph } }
160 ) {
161 const runtime = getEntryRuntime(compilation, entryName);
162 if (options.export) {
163 const exportsInfo = moduleGraph.getExportInfo(
164 module,
165 Array.isArray(options.export) ? options.export[0] : options.export
166 );
167 exportsInfo.setUsed(UsageState.Used, runtime);
168 exportsInfo.canMangleUse = false;
169 } else {
170 const exportsInfo = moduleGraph.getExportsInfo(module);
171 exportsInfo.setUsedInUnknownWay(runtime);
172 }
173 moduleGraph.addExtraReason(module, "used as library export");
174 }
175
176 /**
177 * @param {Compilation} compilation the compilation
178 * @returns {string[]} the prefix
179 */
180 _getPrefix(compilation) {
181 return this.prefix === "global"
182 ? [compilation.runtimeTemplate.globalObject]
183 : this.prefix;
184 }
185
186 /**
187 * @param {AssignLibraryPluginParsed} options the library options
188 * @param {Chunk} chunk the chunk
189 * @param {Compilation} compilation the compilation
190 * @returns {Array<string>} the resolved full name
191 */
192 _getResolvedFullName(options, chunk, compilation) {
193 const prefix = this._getPrefix(compilation);
194 const fullName = options.name ? prefix.concat(options.name) : prefix;
195 return fullName.map(n =>
196 compilation.getPath(n, {
197 chunk
198 })
199 );
200 }
201
202 /**
203 * @param {Source} source source
204 * @param {RenderContext} renderContext render context
205 * @param {LibraryContext<T>} libraryContext context
206 * @returns {Source} source with library export
207 */
208 render(source, { chunk }, { options, compilation }) {
209 const fullNameResolved = this._getResolvedFullName(
210 options,
211 chunk,
212 compilation
213 );
214 if (this.declare) {
215 const base = fullNameResolved[0];
216 if (!isNameValid(base)) {
217 throw new Error(
218 `Library name base (${base}) must be a valid identifier when using a var declaring library type. Either use a valid identifier (e. g. ${Template.toIdentifier(
219 base
220 )}) or use a different library type (e. g. 'type: "global"', which assign a property on the global scope instead of declaring a variable). ${
221 AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE
222 }`
223 );
224 }
225 source = new ConcatSource(`${this.declare} ${base};\n`, source);
226 }
227 return source;
228 }
229
230 /**
231 * @param {Module} module the exporting entry module
232 * @param {RenderContext} renderContext render context
233 * @param {LibraryContext<T>} libraryContext context
234 * @returns {string | undefined} bailout reason
235 */
236 embedInRuntimeBailout(
237 module,
238 { chunk, codeGenerationResults },
239 { options, compilation }
240 ) {
241 const { data } = codeGenerationResults.get(module, chunk.runtime);
242 const topLevelDeclarations =
243 (data && data.get("topLevelDeclarations")) ||
244 (module.buildInfo && module.buildInfo.topLevelDeclarations);
245 if (!topLevelDeclarations)
246 return "it doesn't tell about top level declarations.";
247 const fullNameResolved = this._getResolvedFullName(
248 options,
249 chunk,
250 compilation
251 );
252 const base = fullNameResolved[0];
253 if (topLevelDeclarations.has(base))
254 return `it declares '${base}' on top-level, which conflicts with the current library output.`;
255 }
256
257 /**
258 * @param {RenderContext} renderContext render context
259 * @param {LibraryContext<T>} libraryContext context
260 * @returns {string | undefined} bailout reason
261 */
262 strictRuntimeBailout({ chunk }, { options, compilation }) {
263 if (
264 this.declare ||
265 this.prefix === "global" ||
266 this.prefix.length > 0 ||
267 !options.name
268 ) {
269 return;
270 }
271 return "a global variable is assign and maybe created";
272 }
273
274 /**
275 * @param {Source} source source
276 * @param {Module} module module
277 * @param {StartupRenderContext} renderContext render context
278 * @param {LibraryContext<T>} libraryContext context
279 * @returns {Source} source with library export
280 */
281 renderStartup(
282 source,
283 module,
284 { moduleGraph, chunk },
285 { options, compilation }
286 ) {
287 const fullNameResolved = this._getResolvedFullName(
288 options,
289 chunk,
290 compilation
291 );
292 const staticExports = this.unnamed === "static";
293 const exportAccess = options.export
294 ? propertyAccess(
295 Array.isArray(options.export) ? options.export : [options.export]
296 )
297 : "";
298 const result = new ConcatSource(source);
299 if (staticExports) {
300 const exportsInfo = moduleGraph.getExportsInfo(module);
301 const exportTarget = accessWithInit(
302 fullNameResolved,
303 this._getPrefix(compilation).length,
304 true
305 );
306 for (const exportInfo of exportsInfo.orderedExports) {
307 if (!exportInfo.provided) continue;
308 const nameAccess = propertyAccess([exportInfo.name]);
309 result.add(
310 `${exportTarget}${nameAccess} = ${RuntimeGlobals.exports}${exportAccess}${nameAccess};\n`
311 );
312 }
313 result.add(
314 `Object.defineProperty(${exportTarget}, "__esModule", { value: true });\n`
315 );
316 } else if (options.name ? this.named === "copy" : this.unnamed === "copy") {
317 result.add(
318 `var __webpack_export_target__ = ${accessWithInit(
319 fullNameResolved,
320 this._getPrefix(compilation).length,
321 true
322 )};\n`
323 );
324 /** @type {string} */
325 let exports = RuntimeGlobals.exports;
326 if (exportAccess) {
327 result.add(
328 `var __webpack_exports_export__ = ${RuntimeGlobals.exports}${exportAccess};\n`
329 );
330 exports = "__webpack_exports_export__";
331 }
332 result.add(
333 `for(var __webpack_i__ in ${exports}) __webpack_export_target__[__webpack_i__] = ${exports}[__webpack_i__];\n`
334 );
335 result.add(
336 `if(${exports}.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });\n`
337 );
338 } else {
339 result.add(
340 `${accessWithInit(
341 fullNameResolved,
342 this._getPrefix(compilation).length,
343 false
344 )} = ${RuntimeGlobals.exports}${exportAccess};\n`
345 );
346 }
347 return result;
348 }
349
350 /**
351 * @param {Chunk} chunk the chunk
352 * @param {Set<string>} set runtime requirements
353 * @param {LibraryContext<T>} libraryContext context
354 * @returns {void}
355 */
356 runtimeRequirements(chunk, set, libraryContext) {
357 set.add(RuntimeGlobals.exports);
358 }
359
360 /**
361 * @param {Chunk} chunk the chunk
362 * @param {Hash} hash hash
363 * @param {ChunkHashContext} chunkHashContext chunk hash context
364 * @param {LibraryContext<T>} libraryContext context
365 * @returns {void}
366 */
367 chunkHash(chunk, hash, chunkHashContext, { options, compilation }) {
368 hash.update("AssignLibraryPlugin");
369 const fullNameResolved = this._getResolvedFullName(
370 options,
371 chunk,
372 compilation
373 );
374 if (options.name ? this.named === "copy" : this.unnamed === "copy") {
375 hash.update("copy");
376 }
377 if (this.declare) {
378 hash.update(this.declare);
379 }
380 hash.update(fullNameResolved.join("."));
381 if (options.export) {
382 hash.update(`${options.export}`);
383 }
384 }
385}
386
387module.exports = AssignLibraryPlugin;
Note: See TracBrowser for help on using the repository browser.