webpack 5.80.0 → 5.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

Files changed (135) hide show
  1. package/bin/webpack.js +13 -2
  2. package/lib/AsyncDependenciesBlock.js +8 -0
  3. package/lib/CodeGenerationResults.js +2 -2
  4. package/lib/Compilation.js +4 -2
  5. package/lib/ContextModule.js +8 -0
  6. package/lib/CssModule.js +169 -0
  7. package/lib/DefinePlugin.js +81 -44
  8. package/lib/DelegatedModule.js +5 -0
  9. package/lib/DependenciesBlock.js +8 -0
  10. package/lib/Dependency.js +8 -0
  11. package/lib/DllModule.js +8 -0
  12. package/lib/ExportsInfo.js +3 -0
  13. package/lib/ExternalModule.js +8 -0
  14. package/lib/FileSystemInfo.js +8 -0
  15. package/lib/LoaderOptionsPlugin.js +12 -2
  16. package/lib/Module.js +8 -0
  17. package/lib/ModuleBuildError.js +9 -0
  18. package/lib/ModuleError.js +9 -0
  19. package/lib/ModuleFilenameHelpers.js +113 -4
  20. package/lib/ModuleParseError.js +9 -0
  21. package/lib/ModuleTypeConstants.js +21 -0
  22. package/lib/ModuleWarning.js +9 -0
  23. package/lib/NormalModule.js +8 -0
  24. package/lib/NormalModuleFactory.js +15 -3
  25. package/lib/RawModule.js +8 -0
  26. package/lib/WebpackError.js +8 -0
  27. package/lib/WebpackOptionsApply.js +33 -40
  28. package/lib/asset/RawDataUrlModule.js +8 -0
  29. package/lib/cache/MemoryWithGcCachePlugin.js +2 -0
  30. package/lib/cache/ResolverCachePlugin.js +3 -0
  31. package/lib/config/defaults.js +1 -0
  32. package/lib/config/normalization.js +1 -0
  33. package/lib/container/ContainerEntryModule.js +5 -0
  34. package/lib/container/ContainerExposedDependency.js +9 -0
  35. package/lib/container/FallbackDependency.js +6 -0
  36. package/lib/container/FallbackModule.js +5 -0
  37. package/lib/container/RemoteModule.js +5 -0
  38. package/lib/css/CssGenerator.js +4 -0
  39. package/lib/css/CssLoadingRuntimeModule.js +9 -2
  40. package/lib/css/CssModulesPlugin.js +201 -57
  41. package/lib/css/CssParser.js +270 -147
  42. package/lib/css/walkCssTokens.js +121 -65
  43. package/lib/debug/ProfilingPlugin.js +2 -0
  44. package/lib/dependencies/AMDDefineDependency.js +8 -0
  45. package/lib/dependencies/AMDRequireArrayDependency.js +8 -0
  46. package/lib/dependencies/AMDRequireContextDependency.js +9 -0
  47. package/lib/dependencies/AMDRequireDependency.js +8 -0
  48. package/lib/dependencies/CachedConstDependency.js +8 -0
  49. package/lib/dependencies/CommonJsDependencyHelpers.js +9 -0
  50. package/lib/dependencies/CommonJsExportRequireDependency.js +8 -0
  51. package/lib/dependencies/CommonJsExportsDependency.js +8 -0
  52. package/lib/dependencies/CommonJsExportsParserPlugin.js +65 -3
  53. package/lib/dependencies/CommonJsFullRequireDependency.js +8 -0
  54. package/lib/dependencies/CommonJsRequireContextDependency.js +9 -0
  55. package/lib/dependencies/CommonJsSelfReferenceDependency.js +8 -0
  56. package/lib/dependencies/ConstDependency.js +8 -0
  57. package/lib/dependencies/ContextDependency.js +8 -0
  58. package/lib/dependencies/ContextElementDependency.js +8 -0
  59. package/lib/dependencies/CreateScriptUrlDependency.js +8 -0
  60. package/lib/dependencies/CssExportDependency.js +8 -0
  61. package/lib/dependencies/CssImportDependency.js +52 -1
  62. package/lib/dependencies/CssLocalIdentifierDependency.js +8 -0
  63. package/lib/dependencies/CssSelfLocalIdentifierDependency.js +8 -0
  64. package/lib/dependencies/CssUrlDependency.js +8 -0
  65. package/lib/dependencies/DllEntryDependency.js +9 -0
  66. package/lib/dependencies/ExportsInfoDependency.js +5 -0
  67. package/lib/dependencies/HarmonyAcceptDependency.js +8 -0
  68. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +8 -0
  69. package/lib/dependencies/HarmonyExportExpressionDependency.js +8 -0
  70. package/lib/dependencies/HarmonyExportHeaderDependency.js +8 -0
  71. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +14 -0
  72. package/lib/dependencies/HarmonyExportSpecifierDependency.js +8 -0
  73. package/lib/dependencies/HarmonyImportDependency.js +8 -0
  74. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +1 -0
  75. package/lib/dependencies/HarmonyImportSpecifierDependency.js +8 -0
  76. package/lib/dependencies/ImportContextDependency.js +9 -0
  77. package/lib/dependencies/ImportDependency.js +8 -0
  78. package/lib/dependencies/JsonExportsDependency.js +8 -0
  79. package/lib/dependencies/LocalModuleDependency.js +8 -0
  80. package/lib/dependencies/ModuleDecoratorDependency.js +8 -0
  81. package/lib/dependencies/ModuleDependency.js +8 -0
  82. package/lib/dependencies/ProvidedDependency.js +8 -0
  83. package/lib/dependencies/PureExpressionDependency.js +8 -0
  84. package/lib/dependencies/RequireEnsureDependency.js +8 -0
  85. package/lib/dependencies/RequireHeaderDependency.js +5 -0
  86. package/lib/dependencies/RequireResolveContextDependency.js +9 -0
  87. package/lib/dependencies/RequireResolveHeaderDependency.js +5 -0
  88. package/lib/dependencies/RuntimeRequirementsDependency.js +8 -0
  89. package/lib/dependencies/StaticExportsDependency.js +8 -0
  90. package/lib/dependencies/URLDependency.js +8 -0
  91. package/lib/dependencies/UnsupportedDependency.js +8 -0
  92. package/lib/dependencies/WebAssemblyExportImportedDependency.js +8 -0
  93. package/lib/dependencies/WebAssemblyImportDependency.js +8 -0
  94. package/lib/dependencies/WorkerDependency.js +8 -0
  95. package/lib/index.js +1 -0
  96. package/lib/javascript/BasicEvaluatedExpression.js +108 -1
  97. package/lib/javascript/JavascriptParser.js +133 -12
  98. package/lib/json/JsonData.js +25 -0
  99. package/lib/json/JsonGenerator.js +15 -3
  100. package/lib/json/JsonModulesPlugin.js +1 -0
  101. package/lib/json/JsonParser.js +2 -1
  102. package/lib/library/ModuleLibraryPlugin.js +2 -1
  103. package/lib/optimize/RealContentHashPlugin.js +6 -0
  104. package/lib/runtime/AutoPublicPathRuntimeModule.js +6 -1
  105. package/lib/runtime/GetChunkFilenameRuntimeModule.js +4 -0
  106. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +22 -3
  107. package/lib/schemes/DataUriPlugin.js +4 -0
  108. package/lib/schemes/HttpUriPlugin.js +38 -0
  109. package/lib/serialization/ObjectMiddleware.js +2 -0
  110. package/lib/sharing/ConsumeSharedModule.js +8 -0
  111. package/lib/sharing/ConsumeSharedRuntimeModule.js +9 -3
  112. package/lib/sharing/ProvideSharedDependency.js +6 -0
  113. package/lib/sharing/ProvideSharedModule.js +5 -0
  114. package/lib/sharing/ShareRuntimeModule.js +7 -4
  115. package/lib/sharing/utils.js +293 -7
  116. package/lib/stats/DefaultStatsPrinterPlugin.js +25 -0
  117. package/lib/util/LazySet.js +10 -2
  118. package/lib/util/MapHelpers.js +19 -5
  119. package/lib/util/StackedCacheMap.js +6 -0
  120. package/lib/util/StringXor.js +51 -0
  121. package/lib/util/binarySearchBounds.js +49 -0
  122. package/lib/util/compileBooleanMatcher.js +31 -0
  123. package/lib/util/deprecation.js +8 -0
  124. package/lib/util/identifier.js +4 -0
  125. package/lib/util/internalSerializables.js +1 -0
  126. package/lib/util/numberHash.js +75 -21
  127. package/lib/util/propertyAccess.js +5 -0
  128. package/lib/util/semver.js +1 -1
  129. package/lib/wasm/EnableWasmLoadingPlugin.js +4 -0
  130. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +1 -0
  131. package/lib/wasm-async/AsyncWebAssemblyParser.js +1 -1
  132. package/package.json +4 -5
  133. package/schemas/WebpackOptions.check.js +1 -1
  134. package/schemas/WebpackOptions.json +33 -0
  135. package/types.d.ts +176 -48
@@ -9,13 +9,299 @@ const { join, dirname, readJson } = require("../util/fs");
9
9
 
10
10
  /** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
11
11
 
12
+ // Extreme shorthand only for github. eg: foo/bar
13
+ const RE_URL_GITHUB_EXTREME_SHORT = /^[^/@:.\s][^/@:\s]*\/[^@:\s]*[^/@:\s]#\S+/;
14
+
15
+ // Short url with specific protocol. eg: github:foo/bar
16
+ const RE_GIT_URL_SHORT = /^(github|gitlab|bitbucket|gist):\/?[^/.]+\/?/i;
17
+
18
+ // Currently supported protocols
19
+ const RE_PROTOCOL =
20
+ /^((git\+)?(ssh|https?|file)|git|github|gitlab|bitbucket|gist):$/i;
21
+
22
+ // Has custom protocol
23
+ const RE_CUSTOM_PROTOCOL = /^((git\+)?(ssh|https?|file)|git):\/\//i;
24
+
25
+ // Valid hash format for npm / yarn ...
26
+ const RE_URL_HASH_VERSION = /#(?:semver:)?(.+)/;
27
+
28
+ // Simple hostname validate
29
+ const RE_HOSTNAME = /^(?:[^/.]+(\.[^/]+)+|localhost)$/;
30
+
31
+ // For hostname with colon. eg: ssh://user@github.com:foo/bar
32
+ const RE_HOSTNAME_WITH_COLON =
33
+ /([^/@#:.]+(?:\.[^/@#:.]+)+|localhost):([^#/0-9]+)/;
34
+
35
+ // Reg for url without protocol
36
+ const RE_NO_PROTOCOL = /^([^/@#:.]+(?:\.[^/@#:.]+)+)/;
37
+
38
+ // RegExp for version string
39
+ const VERSION_PATTERN_REGEXP = /^([\d^=v<>~]|[*xX]$)/;
40
+
41
+ // Specific protocol for short url without normal hostname
42
+ const PROTOCOLS_FOR_SHORT = [
43
+ "github:",
44
+ "gitlab:",
45
+ "bitbucket:",
46
+ "gist:",
47
+ "file:"
48
+ ];
49
+
50
+ // Default protocol for git url
51
+ const DEF_GIT_PROTOCOL = "git+ssh://";
52
+
53
+ // thanks to https://github.com/npm/hosted-git-info/blob/latest/git-host-info.js
54
+ const extractCommithashByDomain = {
55
+ "github.com": (pathname, hash) => {
56
+ let [, user, project, type, commithash] = pathname.split("/", 5);
57
+ if (type && type !== "tree") {
58
+ return;
59
+ }
60
+
61
+ if (!type) {
62
+ commithash = hash;
63
+ } else {
64
+ commithash = "#" + commithash;
65
+ }
66
+
67
+ if (project && project.endsWith(".git")) {
68
+ project = project.slice(0, -4);
69
+ }
70
+
71
+ if (!user || !project) {
72
+ return;
73
+ }
74
+
75
+ return commithash;
76
+ },
77
+ "gitlab.com": (pathname, hash) => {
78
+ const path = pathname.slice(1);
79
+ if (path.includes("/-/") || path.includes("/archive.tar.gz")) {
80
+ return;
81
+ }
82
+
83
+ const segments = path.split("/");
84
+ let project = segments.pop();
85
+ if (project.endsWith(".git")) {
86
+ project = project.slice(0, -4);
87
+ }
88
+
89
+ const user = segments.join("/");
90
+ if (!user || !project) {
91
+ return;
92
+ }
93
+
94
+ return hash;
95
+ },
96
+ "bitbucket.org": (pathname, hash) => {
97
+ let [, user, project, aux] = pathname.split("/", 4);
98
+ if (["get"].includes(aux)) {
99
+ return;
100
+ }
101
+
102
+ if (project && project.endsWith(".git")) {
103
+ project = project.slice(0, -4);
104
+ }
105
+
106
+ if (!user || !project) {
107
+ return;
108
+ }
109
+
110
+ return hash;
111
+ },
112
+ "gist.github.com": (pathname, hash) => {
113
+ let [, user, project, aux] = pathname.split("/", 4);
114
+ if (aux === "raw") {
115
+ return;
116
+ }
117
+
118
+ if (!project) {
119
+ if (!user) {
120
+ return;
121
+ }
122
+
123
+ project = user;
124
+ user = null;
125
+ }
126
+
127
+ if (project.endsWith(".git")) {
128
+ project = project.slice(0, -4);
129
+ }
130
+
131
+ return hash;
132
+ }
133
+ };
134
+
135
+ /**
136
+ * extract commit hash from parsed url
137
+ *
138
+ * @inner
139
+ * @param {Object} urlParsed parsed url
140
+ * @returns {string} commithash
141
+ */
142
+ function getCommithash(urlParsed) {
143
+ let { hostname, pathname, hash } = urlParsed;
144
+ hostname = hostname.replace(/^www\./, "");
145
+
146
+ try {
147
+ hash = decodeURIComponent(hash);
148
+ // eslint-disable-next-line no-empty
149
+ } catch (e) {}
150
+
151
+ if (extractCommithashByDomain[hostname]) {
152
+ return extractCommithashByDomain[hostname](pathname, hash) || "";
153
+ }
154
+
155
+ return hash;
156
+ }
157
+
158
+ /**
159
+ * make url right for URL parse
160
+ *
161
+ * @inner
162
+ * @param {string} gitUrl git url
163
+ * @returns {string} fixed url
164
+ */
165
+ function correctUrl(gitUrl) {
166
+ // like:
167
+ // proto://hostname.com:user/repo -> proto://hostname.com/user/repo
168
+ return gitUrl.replace(RE_HOSTNAME_WITH_COLON, "$1/$2");
169
+ }
170
+
171
+ /**
172
+ * make url protocol right for URL parse
173
+ *
174
+ * @inner
175
+ * @param {string} gitUrl git url
176
+ * @returns {string} fixed url
177
+ */
178
+ function correctProtocol(gitUrl) {
179
+ // eg: github:foo/bar#v1.0. Should not add double slash, in case of error parsed `pathname`
180
+ if (RE_GIT_URL_SHORT.test(gitUrl)) {
181
+ return gitUrl;
182
+ }
183
+
184
+ // eg: user@github.com:foo/bar
185
+ if (!RE_CUSTOM_PROTOCOL.test(gitUrl)) {
186
+ return `${DEF_GIT_PROTOCOL}${gitUrl}`;
187
+ }
188
+
189
+ return gitUrl;
190
+ }
191
+
192
+ /**
193
+ * extract git dep version from hash
194
+ *
195
+ * @inner
196
+ * @param {string} hash hash
197
+ * @returns {string} git dep version
198
+ */
199
+ function getVersionFromHash(hash) {
200
+ const matched = hash.match(RE_URL_HASH_VERSION);
201
+
202
+ return (matched && matched[1]) || "";
203
+ }
204
+
205
+ /**
206
+ * if string can be decoded
207
+ *
208
+ * @inner
209
+ * @param {string} str str to be checked
210
+ * @returns {boolean} if can be decoded
211
+ */
212
+ function canBeDecoded(str) {
213
+ try {
214
+ decodeURIComponent(str);
215
+ } catch (e) {
216
+ return false;
217
+ }
218
+
219
+ return true;
220
+ }
221
+
222
+ /**
223
+ * get right dep version from git url
224
+ *
225
+ * @inner
226
+ * @param {string} gitUrl git url
227
+ * @returns {string} dep version
228
+ */
229
+ function getGitUrlVersion(gitUrl) {
230
+ let oriGitUrl = gitUrl;
231
+ // github extreme shorthand
232
+ if (RE_URL_GITHUB_EXTREME_SHORT.test(gitUrl)) {
233
+ gitUrl = "github:" + gitUrl;
234
+ } else {
235
+ gitUrl = correctProtocol(gitUrl);
236
+ }
237
+
238
+ gitUrl = correctUrl(gitUrl);
239
+
240
+ let parsed;
241
+ try {
242
+ parsed = new URL(gitUrl);
243
+ // eslint-disable-next-line no-empty
244
+ } catch (e) {}
245
+
246
+ if (!parsed) {
247
+ return "";
248
+ }
249
+
250
+ const { protocol, hostname, pathname, username, password } = parsed;
251
+ if (!RE_PROTOCOL.test(protocol)) {
252
+ return "";
253
+ }
254
+
255
+ // pathname shouldn't be empty or URL malformed
256
+ if (!pathname || !canBeDecoded(pathname)) {
257
+ return "";
258
+ }
259
+
260
+ // without protocol, there should have auth info
261
+ if (RE_NO_PROTOCOL.test(oriGitUrl) && !username && !password) {
262
+ return "";
263
+ }
264
+
265
+ if (!PROTOCOLS_FOR_SHORT.includes(protocol.toLowerCase())) {
266
+ if (!RE_HOSTNAME.test(hostname)) {
267
+ return "";
268
+ }
269
+
270
+ const commithash = getCommithash(parsed);
271
+ return getVersionFromHash(commithash) || commithash;
272
+ }
273
+
274
+ // for protocol short
275
+ return getVersionFromHash(gitUrl);
276
+ }
277
+
12
278
  /**
13
279
  * @param {string} str maybe required version
14
280
  * @returns {boolean} true, if it looks like a version
15
281
  */
16
- exports.isRequiredVersion = str => {
17
- return /^([\d^=v<>~]|[*xX]$)/.test(str);
18
- };
282
+ function isRequiredVersion(str) {
283
+ return VERSION_PATTERN_REGEXP.test(str);
284
+ }
285
+
286
+ exports.isRequiredVersion = isRequiredVersion;
287
+
288
+ /**
289
+ * @see https://docs.npmjs.com/cli/v7/configuring-npm/package-json#urls-as-dependencies
290
+ * @param {string} versionDesc version to be normalized
291
+ * @returns {string} normalized version
292
+ */
293
+ function normalizeVersion(versionDesc) {
294
+ versionDesc = (versionDesc && versionDesc.trim()) || "";
295
+
296
+ if (isRequiredVersion(versionDesc)) {
297
+ return versionDesc;
298
+ }
299
+
300
+ // add handle for URL Dependencies
301
+ return getGitUrlVersion(versionDesc.toLowerCase());
302
+ }
303
+
304
+ exports.normalizeVersion = normalizeVersion;
19
305
 
20
306
  /**
21
307
  *
@@ -64,27 +350,27 @@ exports.getRequiredVersionFromDescriptionFile = (data, packageName) => {
64
350
  typeof data.optionalDependencies === "object" &&
65
351
  packageName in data.optionalDependencies
66
352
  ) {
67
- return data.optionalDependencies[packageName];
353
+ return normalizeVersion(data.optionalDependencies[packageName]);
68
354
  }
69
355
  if (
70
356
  data.dependencies &&
71
357
  typeof data.dependencies === "object" &&
72
358
  packageName in data.dependencies
73
359
  ) {
74
- return data.dependencies[packageName];
360
+ return normalizeVersion(data.dependencies[packageName]);
75
361
  }
76
362
  if (
77
363
  data.peerDependencies &&
78
364
  typeof data.peerDependencies === "object" &&
79
365
  packageName in data.peerDependencies
80
366
  ) {
81
- return data.peerDependencies[packageName];
367
+ return normalizeVersion(data.peerDependencies[packageName]);
82
368
  }
83
369
  if (
84
370
  data.devDependencies &&
85
371
  typeof data.devDependencies === "object" &&
86
372
  packageName in data.devDependencies
87
373
  ) {
88
- return data.devDependencies[packageName];
374
+ return normalizeVersion(data.devDependencies[packageName]);
89
375
  }
90
376
  };
@@ -12,6 +12,12 @@
12
12
  const DATA_URI_CONTENT_LENGTH = 16;
13
13
  const MAX_MODULE_IDENTIFIER_LENGTH = 80;
14
14
 
15
+ /**
16
+ * @param {number} n a number
17
+ * @param {string} singular singular
18
+ * @param {string} plural plural
19
+ * @returns {string} if n is 1, singular, else plural
20
+ */
15
21
  const plural = (n, singular, plural) => (n === 1 ? singular : plural);
16
22
 
17
23
  /**
@@ -29,6 +35,10 @@ const printSizes = (sizes, { formatSize = n => `${n}` }) => {
29
35
  }
30
36
  };
31
37
 
38
+ /**
39
+ * @param {string} resource resource
40
+ * @returns {string} resource name for display
41
+ */
32
42
  const getResourceName = resource => {
33
43
  const dataUrl = /^data:[^,]+,/.exec(resource);
34
44
  if (!dataUrl) return resource;
@@ -41,6 +51,10 @@ const getResourceName = resource => {
41
51
  )}..`;
42
52
  };
43
53
 
54
+ /**
55
+ * @param {string} name module name
56
+ * @returns {[string,string]} prefix and module name
57
+ */
44
58
  const getModuleName = name => {
45
59
  const [, prefix, resource] = /^(.*!)?([^!]*)$/.exec(name);
46
60
 
@@ -59,6 +73,11 @@ const getModuleName = name => {
59
73
  return [prefix, getResourceName(resource)];
60
74
  };
61
75
 
76
+ /**
77
+ * @param {string} str string
78
+ * @param {function(string): string} fn function to apply to each line
79
+ * @returns {string} joined string
80
+ */
62
81
  const mapLines = (str, fn) => str.split("\n").map(fn).join("\n");
63
82
 
64
83
  /**
@@ -71,6 +90,12 @@ const isValidId = id => {
71
90
  return typeof id === "number" || id;
72
91
  };
73
92
 
93
+ /**
94
+ * @template T
95
+ * @param {Array<T>} list of items
96
+ * @param {number} count number of items to show
97
+ * @returns {string} string representation of list
98
+ */
74
99
  const moreCount = (list, count) => {
75
100
  return list && list.length > 0 ? `+ ${count}` : `${count}`;
76
101
  };
@@ -87,7 +87,7 @@ class LazySet {
87
87
 
88
88
  /**
89
89
  * @param {T} item an item
90
- * @returns {this} itself
90
+ * @returns {LazySet<T>} itself
91
91
  */
92
92
  add(item) {
93
93
  this._set.add(item);
@@ -96,7 +96,7 @@ class LazySet {
96
96
 
97
97
  /**
98
98
  * @param {Iterable<T> | LazySet<T>} iterable a immutable iterable or another immutable LazySet which will eventually be merged into the Set
99
- * @returns {this} itself
99
+ * @returns {LazySet<T>} itself
100
100
  */
101
101
  addAll(iterable) {
102
102
  if (this._deopt) {
@@ -187,12 +187,20 @@ class LazySet {
187
187
  return "LazySet";
188
188
  }
189
189
 
190
+ /**
191
+ * @param {import("../serialization/ObjectMiddleware").ObjectSerializerContext} context context
192
+ */
190
193
  serialize({ write }) {
191
194
  if (this._needMerge) this._merge();
192
195
  write(this._set.size);
193
196
  for (const item of this._set) write(item);
194
197
  }
195
198
 
199
+ /**
200
+ * @template T
201
+ * @param {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} context context
202
+ * @returns {LazySet<T>} lazy set
203
+ */
196
204
  static deserialize({ read }) {
197
205
  const count = read();
198
206
  const items = [];
@@ -6,16 +6,30 @@
6
6
  "use strict";
7
7
 
8
8
  /**
9
+ * getOrInsert is a helper function for maps that allows you to get a value
10
+ * from a map if it exists, or insert a new value if it doesn't. If it value doesn't
11
+ * exist, it will be computed by the provided function.
12
+ *
9
13
  * @template K
10
14
  * @template V
11
- * @param {Map<K, V>} map a map
12
- * @param {K} key the key
13
- * @param {function(): V} computer compute value
14
- * @returns {V} value
15
+ * @param {Map<K, V>} map The map object to check
16
+ * @param {K} key The key to check
17
+ * @param {function(): V} computer function which will compute the value if it doesn't exist
18
+ * @returns {V} The value from the map, or the computed value
19
+ *
20
+ * @example
21
+ * ```js
22
+ * const map = new Map();
23
+ * const value = getOrInsert(map, "key", () => "value");
24
+ * console.log(value); // "value"
25
+ * ```
15
26
  */
16
- exports.provide = (map, key, computer) => {
27
+ exports.getOrInsert = (map, key, computer) => {
28
+ // Grab key from map
17
29
  const value = map.get(key);
30
+ // If the value already exists, return it
18
31
  if (value !== undefined) return value;
32
+ // Otherwise compute the value, set it in the map, and return it
19
33
  const newValue = computer();
20
34
  map.set(key, newValue);
21
35
  return newValue;
@@ -83,6 +83,9 @@ class StackedCacheMap {
83
83
  this.map.clear();
84
84
  }
85
85
 
86
+ /**
87
+ * @returns {number} size of the map
88
+ */
86
89
  get size() {
87
90
  let size = this.map.size;
88
91
  for (const map of this.stack) {
@@ -91,6 +94,9 @@ class StackedCacheMap {
91
94
  return size;
92
95
  }
93
96
 
97
+ /**
98
+ * @returns {Iterator<[K, V]>} iterator
99
+ */
94
100
  [Symbol.iterator]() {
95
101
  const iterators = this.stack.map(map => map[Symbol.iterator]());
96
102
  let current = this.map[Symbol.iterator]();
@@ -5,12 +5,46 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ /** @typedef {import("../util/Hash")} Hash */
9
+
10
+ /**
11
+ * StringXor class provides methods for performing
12
+ * [XOR operations](https://en.wikipedia.org/wiki/Exclusive_or) on strings. In this context
13
+ * we operating on the character codes of two strings, which are represented as
14
+ * [Buffer](https://nodejs.org/api/buffer.html) objects.
15
+ *
16
+ * We use [StringXor in webpack](https://github.com/webpack/webpack/commit/41a8e2ea483a544c4ccd3e6217bdfb80daffca39)
17
+ * to create a hash of the current state of the compilation. By XOR'ing the Module hashes, it
18
+ * doesn't matter if the Module hashes are sorted or not. This is useful because it allows us to avoid sorting the
19
+ * Module hashes.
20
+ *
21
+ * @example
22
+ * ```js
23
+ * const xor = new StringXor();
24
+ * xor.add('hello');
25
+ * xor.add('world');
26
+ * console.log(xor.toString());
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```js
31
+ * const xor = new StringXor();
32
+ * xor.add('foo');
33
+ * xor.add('bar');
34
+ * const hash = createHash('sha256');
35
+ * hash.update(xor.toString());
36
+ * console.log(hash.digest('hex'));
37
+ * ```
38
+ */
8
39
  class StringXor {
9
40
  constructor() {
41
+ /** @type {Buffer|undefined} */
10
42
  this._value = undefined;
11
43
  }
12
44
 
13
45
  /**
46
+ * Adds a string to the current StringXor object.
47
+ *
14
48
  * @param {string} str string
15
49
  * @returns {void}
16
50
  */
@@ -18,6 +52,10 @@ class StringXor {
18
52
  const len = str.length;
19
53
  const value = this._value;
20
54
  if (value === undefined) {
55
+ /**
56
+ * We are choosing to use Buffer.allocUnsafe() because it is often faster than Buffer.alloc() because
57
+ * it allocates a new buffer of the specified size without initializing the memory.
58
+ */
21
59
  const newValue = (this._value = Buffer.allocUnsafe(len));
22
60
  for (let i = 0; i < len; i++) {
23
61
  newValue[i] = str.charCodeAt(i);
@@ -41,11 +79,24 @@ class StringXor {
41
79
  }
42
80
  }
43
81
 
82
+ /**
83
+ * Returns a string that represents the current state of the StringXor object. We chose to use "latin1" encoding
84
+ * here because "latin1" encoding is a single-byte encoding that can represent all characters in the
85
+ * [ISO-8859-1 character set](https://en.wikipedia.org/wiki/ISO/IEC_8859-1). This is useful when working
86
+ * with binary data that needs to be represented as a string.
87
+ *
88
+ * @returns {string} Returns a string that represents the current state of the StringXor object.
89
+ */
44
90
  toString() {
45
91
  const value = this._value;
46
92
  return value === undefined ? "" : value.toString("latin1");
47
93
  }
48
94
 
95
+ /**
96
+ * Updates the hash with the current state of the StringXor object.
97
+ *
98
+ * @param {Hash} hash Hash instance
99
+ */
49
100
  updateHash(hash) {
50
101
  const value = this._value;
51
102
  if (value !== undefined) hash.update(value);
@@ -8,6 +8,28 @@
8
8
  /* cspell:disable-next-line */
9
9
  // Refactor: Peter Somogyvari @petermetz
10
10
 
11
+ /** @typedef {">=" | "<=" | "<" | ">" | "-" } BinarySearchPredicate */
12
+ /** @typedef {"GE" | "GT" | "LT" | "LE" | "EQ" } SearchPredicateSuffix */
13
+
14
+ /**
15
+ * Helper function for compiling binary search functions.
16
+ *
17
+ * The generated code uses a while loop to repeatedly divide the search interval
18
+ * in half until the desired element is found, or the search interval is empty.
19
+ *
20
+ * The following is an example of a generated function for calling `compileSearch("P", "c(x,y)<=0", true, ["y", "c"], false)`:
21
+ *
22
+ * ```js
23
+ * function P(a,l,h,y,c){var i=l-1;while(l<=h){var m=(l+h)>>>1,x=a[m];if(c(x,y)<=0){i=m;l=m+1}else{h=m-1}}return i};
24
+ * ```
25
+ *
26
+ * @param {string} funcName The name of the function to be compiled.
27
+ * @param {string} predicate The predicate / comparison operator to be used in the binary search.
28
+ * @param {boolean} reversed Whether the search should be reversed.
29
+ * @param {string[]} extraArgs Extra arguments to be passed to the function.
30
+ * @param {boolean=} earlyOut Whether the search should return as soon as a match is found.
31
+ * @returns {string} The compiled binary search function.
32
+ */
11
33
  const compileSearch = (funcName, predicate, reversed, extraArgs, earlyOut) => {
12
34
  const code = [
13
35
  "function ",
@@ -43,6 +65,18 @@ const compileSearch = (funcName, predicate, reversed, extraArgs, earlyOut) => {
43
65
  return code.join("");
44
66
  };
45
67
 
68
+ /**
69
+ * This helper functions generate code for two binary search functions:
70
+ * A(): Performs a binary search on an array using the comparison operator specified.
71
+ * P(): Performs a binary search on an array using a _custom comparison function_
72
+ * `c(x,y)` **and** comparison operator specified by `predicate`.
73
+ *
74
+ * @param {BinarySearchPredicate} predicate The predicate / comparison operator to be used in the binary search.
75
+ * @param {boolean} reversed Whether the search should be reversed.
76
+ * @param {SearchPredicateSuffix} suffix The suffix to be used in the function name.
77
+ * @param {boolean=} earlyOut Whether the search should return as soon as a match is found.
78
+ * @returns {function} The compiled binary search function.
79
+ */
46
80
  const compileBoundsSearch = (predicate, reversed, suffix, earlyOut) => {
47
81
  const arg1 = compileSearch(
48
82
  "A",
@@ -77,6 +111,21 @@ return dispatchBinarySearch";
77
111
  return result();
78
112
  };
79
113
 
114
+ /**
115
+ * These functions are used to perform binary searches on arrays.
116
+ *
117
+ * @example
118
+ * ```js
119
+ * const { gt, le} = require("./binarySearchBounds");
120
+ * const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
121
+ *
122
+ * // Find the index of the first element greater than 5
123
+ * const index1 = gt(arr, 5); // index1 === 3
124
+ *
125
+ * // Find the index of the first element less than or equal to 5
126
+ * const index2 = le(arr, 5); // index2 === 4
127
+ * ```
128
+ */
80
129
  module.exports = {
81
130
  ge: compileBoundsSearch(">=", false, "GE"),
82
131
  gt: compileBoundsSearch(">", false, "GT"),