source: trip-planner-front/node_modules/webpack/lib/library/AssignLibraryPlugin.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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