@atlaspack/core 2.12.1-canary.3354

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.
Files changed (215) hide show
  1. package/LICENSE +201 -0
  2. package/index.d.ts +22 -0
  3. package/lib/AssetGraph.js +518 -0
  4. package/lib/Atlaspack.js +587 -0
  5. package/lib/AtlaspackConfig.js +298 -0
  6. package/lib/AtlaspackConfig.schema.js +125 -0
  7. package/lib/BundleGraph.js +1445 -0
  8. package/lib/CommittedAsset.js +133 -0
  9. package/lib/Dependency.js +88 -0
  10. package/lib/Environment.js +128 -0
  11. package/lib/InternalConfig.js +48 -0
  12. package/lib/PackagerRunner.js +519 -0
  13. package/lib/ReporterRunner.js +151 -0
  14. package/lib/RequestTracker.js +1089 -0
  15. package/lib/SymbolPropagation.js +625 -0
  16. package/lib/TargetDescriptor.schema.js +115 -0
  17. package/lib/Transformation.js +536 -0
  18. package/lib/UncommittedAsset.js +342 -0
  19. package/lib/Validation.js +215 -0
  20. package/lib/applyRuntimes.js +279 -0
  21. package/lib/assetUtils.js +189 -0
  22. package/lib/atlaspack-v3/AtlaspackV3.js +74 -0
  23. package/lib/atlaspack-v3/fs.js +30 -0
  24. package/lib/atlaspack-v3/index.js +19 -0
  25. package/lib/atlaspack-v3/jsCallable.js +15 -0
  26. package/lib/atlaspack-v3/plugins/Resolver.js +12 -0
  27. package/lib/atlaspack-v3/plugins/index.js +16 -0
  28. package/lib/atlaspack-v3/worker/index.js +3 -0
  29. package/lib/atlaspack-v3/worker/worker.js +30 -0
  30. package/lib/buildCache.js +18 -0
  31. package/lib/constants.js +21 -0
  32. package/lib/dumpGraphToGraphViz.js +206 -0
  33. package/lib/index.js +106 -0
  34. package/lib/loadAtlaspackPlugin.js +148 -0
  35. package/lib/loadDotEnv.js +54 -0
  36. package/lib/projectPath.js +86 -0
  37. package/lib/public/Asset.js +259 -0
  38. package/lib/public/Bundle.js +231 -0
  39. package/lib/public/BundleGraph.js +193 -0
  40. package/lib/public/BundleGroup.js +44 -0
  41. package/lib/public/Config.js +202 -0
  42. package/lib/public/Dependency.js +131 -0
  43. package/lib/public/Environment.js +244 -0
  44. package/lib/public/MutableBundleGraph.js +184 -0
  45. package/lib/public/PluginOptions.js +71 -0
  46. package/lib/public/Symbols.js +247 -0
  47. package/lib/public/Target.js +64 -0
  48. package/lib/registerCoreWithSerializer.js +45 -0
  49. package/lib/requests/AssetGraphRequest.js +427 -0
  50. package/lib/requests/AssetGraphRequestRust.js +187 -0
  51. package/lib/requests/AssetRequest.js +137 -0
  52. package/lib/requests/AtlaspackBuildRequest.js +78 -0
  53. package/lib/requests/AtlaspackConfigRequest.js +473 -0
  54. package/lib/requests/BundleGraphRequest.js +419 -0
  55. package/lib/requests/ConfigRequest.js +198 -0
  56. package/lib/requests/DevDepRequest.js +166 -0
  57. package/lib/requests/EntryRequest.js +295 -0
  58. package/lib/requests/PackageRequest.js +88 -0
  59. package/lib/requests/PathRequest.js +349 -0
  60. package/lib/requests/TargetRequest.js +1177 -0
  61. package/lib/requests/ValidationRequest.js +66 -0
  62. package/lib/requests/WriteBundleRequest.js +252 -0
  63. package/lib/requests/WriteBundlesRequest.js +153 -0
  64. package/lib/resolveOptions.js +234 -0
  65. package/lib/serializer.js +216 -0
  66. package/lib/serializerCore.browser.js +29 -0
  67. package/lib/serializerCore.js +16 -0
  68. package/lib/summarizeRequest.js +55 -0
  69. package/lib/types.js +35 -0
  70. package/lib/utils.js +160 -0
  71. package/lib/worker.js +170 -0
  72. package/package.json +59 -0
  73. package/src/AssetGraph.js +646 -0
  74. package/src/Atlaspack.js +632 -0
  75. package/src/AtlaspackConfig.js +490 -0
  76. package/src/AtlaspackConfig.schema.js +141 -0
  77. package/src/BundleGraph.js +2193 -0
  78. package/src/CommittedAsset.js +143 -0
  79. package/src/Dependency.js +142 -0
  80. package/src/Environment.js +151 -0
  81. package/src/InternalConfig.js +72 -0
  82. package/src/PackagerRunner.js +790 -0
  83. package/src/ReporterRunner.js +158 -0
  84. package/src/RequestTracker.js +1697 -0
  85. package/src/SymbolPropagation.js +794 -0
  86. package/src/TargetDescriptor.schema.js +136 -0
  87. package/src/Transformation.js +752 -0
  88. package/src/UncommittedAsset.js +426 -0
  89. package/src/Validation.js +223 -0
  90. package/src/applyRuntimes.js +341 -0
  91. package/src/assetUtils.js +254 -0
  92. package/src/atlaspack-v3/AtlaspackV3.js +73 -0
  93. package/src/atlaspack-v3/fs.js +36 -0
  94. package/src/atlaspack-v3/index.js +5 -0
  95. package/src/atlaspack-v3/jsCallable.js +13 -0
  96. package/src/atlaspack-v3/plugins/Resolver.js +9 -0
  97. package/src/atlaspack-v3/plugins/index.js +3 -0
  98. package/src/atlaspack-v3/worker/index.js +8 -0
  99. package/src/atlaspack-v3/worker/worker.js +14 -0
  100. package/src/buildCache.js +15 -0
  101. package/src/constants.js +22 -0
  102. package/src/dumpGraphToGraphViz.js +244 -0
  103. package/src/index.js +22 -0
  104. package/src/loadAtlaspackPlugin.js +239 -0
  105. package/src/loadDotEnv.js +56 -0
  106. package/src/projectPath.js +87 -0
  107. package/src/public/Asset.js +359 -0
  108. package/src/public/Bundle.js +337 -0
  109. package/src/public/BundleGraph.js +335 -0
  110. package/src/public/BundleGroup.js +55 -0
  111. package/src/public/Config.js +261 -0
  112. package/src/public/Dependency.js +176 -0
  113. package/src/public/Environment.js +316 -0
  114. package/src/public/MutableBundleGraph.js +320 -0
  115. package/src/public/PluginOptions.js +99 -0
  116. package/src/public/Symbols.js +315 -0
  117. package/src/public/Target.js +71 -0
  118. package/src/registerCoreWithSerializer.js +34 -0
  119. package/src/requests/AssetGraphRequest.js +577 -0
  120. package/src/requests/AssetGraphRequestRust.js +222 -0
  121. package/src/requests/AssetRequest.js +179 -0
  122. package/src/requests/AtlaspackBuildRequest.js +109 -0
  123. package/src/requests/AtlaspackConfigRequest.js +709 -0
  124. package/src/requests/BundleGraphRequest.js +547 -0
  125. package/src/requests/ConfigRequest.js +287 -0
  126. package/src/requests/DevDepRequest.js +246 -0
  127. package/src/requests/EntryRequest.js +385 -0
  128. package/src/requests/PackageRequest.js +105 -0
  129. package/src/requests/PathRequest.js +454 -0
  130. package/src/requests/TargetRequest.js +1632 -0
  131. package/src/requests/ValidationRequest.js +79 -0
  132. package/src/requests/WriteBundleRequest.js +362 -0
  133. package/src/requests/WriteBundlesRequest.js +209 -0
  134. package/src/resolveOptions.js +278 -0
  135. package/src/serializer.js +255 -0
  136. package/src/serializerCore.browser.js +8 -0
  137. package/src/serializerCore.js +5 -0
  138. package/src/summarizeRequest.js +47 -0
  139. package/src/types.js +581 -0
  140. package/src/utils.js +211 -0
  141. package/src/worker.js +189 -0
  142. package/test/AssetGraph.test.js +679 -0
  143. package/test/Atlaspack.test.js +142 -0
  144. package/test/AtlaspackConfig.test.js +405 -0
  145. package/test/AtlaspackConfigRequest.test.js +993 -0
  146. package/test/BundleGraph.test.js +121 -0
  147. package/test/EntryRequest.test.js +215 -0
  148. package/test/Environment.test.js +99 -0
  149. package/test/InternalAsset.test.js +76 -0
  150. package/test/PackagerRunner.test.js +27 -0
  151. package/test/PublicAsset.test.js +40 -0
  152. package/test/PublicBundle.test.js +68 -0
  153. package/test/PublicDependency.test.js +22 -0
  154. package/test/PublicEnvironment.test.js +27 -0
  155. package/test/PublicMutableBundleGraph.test.js +192 -0
  156. package/test/RequestTracker.test.js +448 -0
  157. package/test/SymbolPropagation.test.js +716 -0
  158. package/test/TargetRequest.test.js +1715 -0
  159. package/test/fixtures/application-targets/package.json +3 -0
  160. package/test/fixtures/atlaspack/index.js +1 -0
  161. package/test/fixtures/atlaspack/other.js +3 -0
  162. package/test/fixtures/atlaspack/package.json +1 -0
  163. package/test/fixtures/atlaspack/yarn.lock +0 -0
  164. package/test/fixtures/bundle.js +10 -0
  165. package/test/fixtures/common-targets/package.json +24 -0
  166. package/test/fixtures/common-targets-ignore/package.json +13 -0
  167. package/test/fixtures/config/.atlaspackrc +6 -0
  168. package/test/fixtures/config/subfolder/.atlaspackrc +6 -0
  169. package/test/fixtures/config-extends-not-found/.atlaspackrc +3 -0
  170. package/test/fixtures/config-extends-not-found/.atlaspackrc-json5 +3 -0
  171. package/test/fixtures/config-extends-not-found/.atlaspackrc-multiple +3 -0
  172. package/test/fixtures/config-extends-not-found/.atlaspackrc-node-modules +3 -0
  173. package/test/fixtures/config-malformed/.atlaspackrc +3 -0
  174. package/test/fixtures/config-node-pipeline/.atlaspackrc +6 -0
  175. package/test/fixtures/config-plugin-not-found/.atlaspackrc +6 -0
  176. package/test/fixtures/context/package.json +8 -0
  177. package/test/fixtures/custom-format-infer-ext/package.json +6 -0
  178. package/test/fixtures/custom-format-infer-type/package.json +7 -0
  179. package/test/fixtures/custom-format-mismatch/package.json +8 -0
  180. package/test/fixtures/custom-targets/package.json +20 -0
  181. package/test/fixtures/custom-targets-distdir/package.json +11 -0
  182. package/test/fixtures/duplicate-targets/package.json +4 -0
  183. package/test/fixtures/glob-like/[entry].js +0 -0
  184. package/test/fixtures/invalid-distpath/package.json +11 -0
  185. package/test/fixtures/invalid-engines/package.json +12 -0
  186. package/test/fixtures/invalid-source-missing/package.json +5 -0
  187. package/test/fixtures/invalid-source-not-file/package.json +5 -0
  188. package/test/fixtures/invalid-source-not-file/src/index.js +1 -0
  189. package/test/fixtures/invalid-target-source-missing/package.json +9 -0
  190. package/test/fixtures/invalid-target-source-not-file/package.json +9 -0
  191. package/test/fixtures/invalid-target-source-not-file/src/index.js +1 -0
  192. package/test/fixtures/invalid-targets/package.json +19 -0
  193. package/test/fixtures/library-custom-scopehoist/package.json +9 -0
  194. package/test/fixtures/library-scopehoist/package.json +8 -0
  195. package/test/fixtures/local-plugin-config-pkg/.atlaspackrc +3 -0
  196. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/index.json +8 -0
  197. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/local-plugin.js +7 -0
  198. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/package.json +7 -0
  199. package/test/fixtures/main-format-mismatch/package.json +8 -0
  200. package/test/fixtures/main-global/package.json +8 -0
  201. package/test/fixtures/main-mjs/package.json +8 -0
  202. package/test/fixtures/module-a.js +1 -0
  203. package/test/fixtures/module-b.js +1 -0
  204. package/test/fixtures/plugins/local-plugin.js +7 -0
  205. package/test/fixtures/plugins/node_modules/atlaspack-transformer-bad-engines/index.js +7 -0
  206. package/test/fixtures/plugins/node_modules/atlaspack-transformer-bad-engines/package.json +7 -0
  207. package/test/fixtures/plugins/node_modules/atlaspack-transformer-no-engines/index.js +7 -0
  208. package/test/fixtures/plugins/node_modules/atlaspack-transformer-no-engines/package.json +4 -0
  209. package/test/fixtures/targets-default-distdir-none/package.json +5 -0
  210. package/test/fixtures/targets-default-distdir-one/package.json +8 -0
  211. package/test/fixtures/targets-default-distdir-two/package.json +18 -0
  212. package/test/requests/ConfigRequest.test.js +254 -0
  213. package/test/serializer.test.js +302 -0
  214. package/test/test-utils.js +80 -0
  215. package/test/utils.test.js +43 -0
@@ -0,0 +1,426 @@
1
+ // @flow strict-local
2
+
3
+ import type {
4
+ AST,
5
+ Blob,
6
+ DependencyOptions,
7
+ FileCreateInvalidation,
8
+ GenerateOutput,
9
+ PackageName,
10
+ TransformerResult,
11
+ } from '@atlaspack/types';
12
+ import type {Asset, Dependency, AtlaspackOptions, Invalidations} from './types';
13
+
14
+ import invariant from 'assert';
15
+ import {Readable} from 'stream';
16
+ import SourceMap from '@parcel/source-map';
17
+ import {
18
+ blobToStream,
19
+ bufferStream,
20
+ streamFromPromise,
21
+ TapStream,
22
+ loadSourceMap,
23
+ SOURCEMAP_RE,
24
+ } from '@atlaspack/utils';
25
+ import {hashString, hashBuffer, Hash} from '@atlaspack/rust';
26
+ import {serializeRaw} from './serializer';
27
+ import {createDependency, mergeDependencies} from './Dependency';
28
+ import {mergeEnvironments} from './Environment';
29
+ import {ATLASPACK_VERSION} from './constants';
30
+ import {createAsset, createAssetIdFromOptions} from './assetUtils';
31
+ import {BundleBehaviorNames} from './types';
32
+ import {invalidateOnFileCreateToInternal, createInvalidations} from './utils';
33
+ import {type ProjectPath, fromProjectPath} from './projectPath';
34
+
35
+ type UncommittedAssetOptions = {|
36
+ value: Asset,
37
+ options: AtlaspackOptions,
38
+ content?: ?Blob,
39
+ mapBuffer?: ?Buffer,
40
+ ast?: ?AST,
41
+ isASTDirty?: ?boolean,
42
+ idBase?: ?string,
43
+ invalidations?: Invalidations,
44
+ |};
45
+
46
+ export default class UncommittedAsset {
47
+ value: Asset;
48
+ options: AtlaspackOptions;
49
+ content: ?(Blob | Promise<Buffer>);
50
+ mapBuffer: ?Buffer;
51
+ sourceContent: ?string;
52
+ map: ?SourceMap;
53
+ ast: ?AST;
54
+ isASTDirty: boolean;
55
+ idBase: ?string;
56
+ invalidations: Invalidations;
57
+ generate: ?() => Promise<GenerateOutput>;
58
+
59
+ constructor({
60
+ value,
61
+ options,
62
+ content,
63
+ mapBuffer,
64
+ ast,
65
+ isASTDirty,
66
+ idBase,
67
+ invalidations,
68
+ }: UncommittedAssetOptions) {
69
+ this.value = value;
70
+ this.options = options;
71
+ this.content = content;
72
+ this.mapBuffer = mapBuffer;
73
+ this.ast = ast;
74
+ this.isASTDirty = isASTDirty || false;
75
+ this.idBase = idBase;
76
+ this.invalidations = invalidations || createInvalidations();
77
+ }
78
+
79
+ /*
80
+ * Prepares the asset for being serialized to the cache by committing its
81
+ * content and map of the asset to the cache.
82
+ */
83
+ async commit(): Promise<void> {
84
+ // If there is a dirty AST, clear out any old content and map as these
85
+ // must be regenerated later and shouldn't be committed.
86
+ if (this.ast != null && this.isASTDirty) {
87
+ this.content = null;
88
+ this.mapBuffer = null;
89
+ }
90
+
91
+ let size = 0;
92
+ let outputHash = '';
93
+ let contentKey = this.content == null ? null : this.getCacheKey('content');
94
+ let mapKey = this.mapBuffer == null ? null : this.getCacheKey('map');
95
+ let astKey = this.ast == null ? null : this.getCacheKey('ast');
96
+
97
+ // Since we can only read from the stream once, compute the content length
98
+ // and hash while it's being written to the cache.
99
+ await Promise.all([
100
+ contentKey != null &&
101
+ this.commitContent(contentKey).then(
102
+ s => ((size = s.size), (outputHash = s.hash)),
103
+ ),
104
+ this.mapBuffer != null &&
105
+ mapKey != null &&
106
+ this.options.cache.setBlob(mapKey, this.mapBuffer),
107
+ astKey != null &&
108
+ this.options.cache.setBlob(astKey, serializeRaw(this.ast)),
109
+ ]);
110
+ this.value.contentKey = contentKey;
111
+ this.value.mapKey = mapKey;
112
+ this.value.astKey = astKey;
113
+ this.value.outputHash = outputHash;
114
+
115
+ if (this.content != null) {
116
+ this.value.stats.size = size;
117
+ }
118
+
119
+ this.value.isLargeBlob = this.content instanceof Readable;
120
+ this.value.committed = true;
121
+ }
122
+
123
+ async commitContent(
124
+ contentKey: string,
125
+ ): Promise<{|size: number, hash: string|}> {
126
+ let content = await this.content;
127
+ if (content == null) {
128
+ return {size: 0, hash: ''};
129
+ }
130
+
131
+ let size = 0;
132
+ if (content instanceof Readable) {
133
+ let hash = new Hash();
134
+ await this.options.cache.setStream(
135
+ contentKey,
136
+ content.pipe(
137
+ new TapStream(buf => {
138
+ hash.writeBuffer(buf);
139
+ size += buf.length;
140
+ }),
141
+ ),
142
+ );
143
+
144
+ return {size, hash: hash.finish()};
145
+ }
146
+
147
+ let hash;
148
+ if (typeof content === 'string') {
149
+ hash = hashString(content);
150
+ size = Buffer.byteLength(content);
151
+ } else {
152
+ hash = hashBuffer(content);
153
+ size = content.length;
154
+ }
155
+
156
+ await this.options.cache.setBlob(contentKey, content);
157
+ return {size, hash};
158
+ }
159
+
160
+ async getCode(): Promise<string> {
161
+ if (this.ast != null && this.isASTDirty) {
162
+ throw new Error(
163
+ 'Cannot call getCode() on an asset with a dirty AST. For transformers, implement canReuseAST() and check asset.isASTDirty.',
164
+ );
165
+ }
166
+
167
+ let content = await this.content;
168
+ if (typeof content === 'string' || content instanceof Buffer) {
169
+ return content.toString();
170
+ } else if (content != null) {
171
+ this.content = bufferStream(content);
172
+ return (await this.content).toString();
173
+ }
174
+
175
+ invariant(false, 'Internal error: missing content');
176
+ }
177
+
178
+ async getBuffer(): Promise<Buffer> {
179
+ let content = await this.content;
180
+ if (content == null) {
181
+ return Buffer.alloc(0);
182
+ } else if (content instanceof Buffer) {
183
+ return content;
184
+ } else if (typeof content === 'string') {
185
+ return Buffer.from(content);
186
+ }
187
+
188
+ this.content = bufferStream(content);
189
+ return this.content;
190
+ }
191
+
192
+ getStream(): Readable {
193
+ if (this.content instanceof Readable) {
194
+ // Remove content if it's a stream, as it should not be reused.
195
+ let content = this.content;
196
+ this.content = null;
197
+ return content;
198
+ }
199
+
200
+ if (this.content instanceof Promise) {
201
+ return streamFromPromise(this.content);
202
+ }
203
+
204
+ return blobToStream(this.content ?? Buffer.alloc(0));
205
+ }
206
+
207
+ setCode(code: string) {
208
+ this.content = code;
209
+ this.clearAST();
210
+ }
211
+
212
+ setBuffer(buffer: Buffer) {
213
+ this.content = buffer;
214
+ this.clearAST();
215
+ }
216
+
217
+ setStream(stream: Readable) {
218
+ this.content = stream;
219
+ this.clearAST();
220
+ }
221
+
222
+ async loadExistingSourcemap(): Promise<?SourceMap> {
223
+ if (this.map) {
224
+ return this.map;
225
+ }
226
+
227
+ let code = await this.getCode();
228
+ let map = await loadSourceMap(
229
+ fromProjectPath(this.options.projectRoot, this.value.filePath),
230
+ code,
231
+ {
232
+ fs: this.options.inputFS,
233
+ projectRoot: this.options.projectRoot,
234
+ },
235
+ );
236
+
237
+ if (map) {
238
+ this.map = map;
239
+ this.mapBuffer = map.toBuffer();
240
+ this.setCode(code.replace(SOURCEMAP_RE, ''));
241
+ }
242
+
243
+ return this.map;
244
+ }
245
+
246
+ getMapBuffer(): Promise<?Buffer> {
247
+ return Promise.resolve(this.mapBuffer);
248
+ }
249
+
250
+ async getMap(): Promise<?SourceMap> {
251
+ if (this.map == null) {
252
+ let mapBuffer = this.mapBuffer ?? (await this.getMapBuffer());
253
+ if (mapBuffer) {
254
+ // Get sourcemap from flatbuffer
255
+ this.map = new SourceMap(this.options.projectRoot, mapBuffer);
256
+ }
257
+ }
258
+
259
+ return this.map;
260
+ }
261
+
262
+ setMap(map: ?SourceMap): void {
263
+ // If we have sourceContent available, it means this asset is source code without
264
+ // a previous source map. Ensure that the map set by the transformer has the original
265
+ // source content available.
266
+ if (map != null && this.sourceContent != null) {
267
+ map.setSourceContent(
268
+ fromProjectPath(this.options.projectRoot, this.value.filePath),
269
+ // $FlowFixMe
270
+ this.sourceContent,
271
+ );
272
+ this.sourceContent = null;
273
+ }
274
+
275
+ this.map = map;
276
+ this.mapBuffer = this.map?.toBuffer();
277
+ }
278
+
279
+ getAST(): Promise<?AST> {
280
+ return Promise.resolve(this.ast);
281
+ }
282
+
283
+ setAST(ast: AST): void {
284
+ this.ast = ast;
285
+ this.isASTDirty = true;
286
+ this.value.astGenerator = {
287
+ type: ast.type,
288
+ version: ast.version,
289
+ };
290
+ }
291
+
292
+ clearAST() {
293
+ this.ast = null;
294
+ this.isASTDirty = false;
295
+ this.value.astGenerator = null;
296
+ }
297
+
298
+ getCacheKey(key: string): string {
299
+ return hashString(ATLASPACK_VERSION + key + this.value.id);
300
+ }
301
+
302
+ addDependency(opts: DependencyOptions): string {
303
+ // eslint-disable-next-line no-unused-vars
304
+ let {env, symbols, ...rest} = opts;
305
+ let dep = createDependency(this.options.projectRoot, {
306
+ ...rest,
307
+ // $FlowFixMe "convert" the $ReadOnlyMaps to the interal mutable one
308
+ symbols,
309
+ env: mergeEnvironments(this.options.projectRoot, this.value.env, env),
310
+ sourceAssetId: this.value.id,
311
+ sourcePath: fromProjectPath(
312
+ this.options.projectRoot,
313
+ this.value.filePath,
314
+ ),
315
+ });
316
+ let existing = this.value.dependencies.get(dep.id);
317
+ if (existing) {
318
+ mergeDependencies(existing, dep);
319
+ } else {
320
+ this.value.dependencies.set(dep.id, dep);
321
+ }
322
+ return dep.id;
323
+ }
324
+
325
+ invalidateOnFileChange(filePath: ProjectPath) {
326
+ this.invalidations.invalidateOnFileChange.add(filePath);
327
+ }
328
+
329
+ invalidateOnFileCreate(invalidation: FileCreateInvalidation) {
330
+ this.invalidations.invalidateOnFileCreate.push(
331
+ invalidateOnFileCreateToInternal(this.options.projectRoot, invalidation),
332
+ );
333
+ }
334
+
335
+ invalidateOnEnvChange(key: string) {
336
+ this.invalidations.invalidateOnEnvChange.add(key);
337
+ }
338
+
339
+ invalidateOnBuild() {
340
+ this.invalidations.invalidateOnBuild = true;
341
+ }
342
+
343
+ invalidateOnStartup() {
344
+ this.invalidations.invalidateOnStartup = true;
345
+ }
346
+
347
+ getDependencies(): Array<Dependency> {
348
+ return Array.from(this.value.dependencies.values());
349
+ }
350
+
351
+ createChildAsset(
352
+ result: TransformerResult,
353
+ plugin: PackageName,
354
+ configPath: ProjectPath,
355
+ configKeyPath?: string,
356
+ ): UncommittedAsset {
357
+ let content = result.content ?? null;
358
+
359
+ let asset = new UncommittedAsset({
360
+ value: createAsset(this.options.projectRoot, {
361
+ idBase: this.idBase,
362
+ filePath: this.value.filePath,
363
+ type: result.type,
364
+ bundleBehavior:
365
+ result.bundleBehavior ??
366
+ (this.value.bundleBehavior == null
367
+ ? null
368
+ : BundleBehaviorNames[this.value.bundleBehavior]),
369
+ isBundleSplittable:
370
+ result.isBundleSplittable ?? this.value.isBundleSplittable,
371
+ isSource: this.value.isSource,
372
+ env: mergeEnvironments(
373
+ this.options.projectRoot,
374
+ this.value.env,
375
+ result.env,
376
+ ),
377
+ dependencies:
378
+ this.value.type === result.type
379
+ ? new Map(this.value.dependencies)
380
+ : new Map(),
381
+ meta: {
382
+ ...this.value.meta,
383
+ ...result.meta,
384
+ },
385
+ pipeline:
386
+ result.pipeline ??
387
+ (this.value.type === result.type ? this.value.pipeline : null),
388
+ stats: {
389
+ time: 0,
390
+ size: this.value.stats.size,
391
+ },
392
+ // $FlowFixMe
393
+ symbols: result.symbols,
394
+ sideEffects: result.sideEffects ?? this.value.sideEffects,
395
+ uniqueKey: result.uniqueKey,
396
+ astGenerator: result.ast
397
+ ? {type: result.ast.type, version: result.ast.version}
398
+ : null,
399
+ plugin,
400
+ configPath,
401
+ configKeyPath,
402
+ }),
403
+ options: this.options,
404
+ content,
405
+ ast: result.ast,
406
+ isASTDirty: result.ast === this.ast ? this.isASTDirty : true,
407
+ mapBuffer: result.map ? result.map.toBuffer() : null,
408
+ idBase: this.idBase,
409
+ invalidations: this.invalidations,
410
+ });
411
+
412
+ let dependencies = result.dependencies;
413
+ if (dependencies) {
414
+ for (let dep of dependencies) {
415
+ asset.addDependency(dep);
416
+ }
417
+ }
418
+
419
+ return asset;
420
+ }
421
+
422
+ updateId() {
423
+ // $FlowFixMe - this is fine
424
+ this.value.id = createAssetIdFromOptions(this.value);
425
+ }
426
+ }
@@ -0,0 +1,223 @@
1
+ // @flow strict-local
2
+
3
+ import type {WorkerApi} from '@atlaspack/workers';
4
+ import type {AssetGroup, AtlaspackOptions, ReportFn} from './types';
5
+ import type {Validator, ValidateResult} from '@atlaspack/types';
6
+ import type {Diagnostic} from '@atlaspack/diagnostic';
7
+
8
+ import path from 'path';
9
+ import {resolveConfig} from '@atlaspack/utils';
10
+ import logger, {PluginLogger} from '@atlaspack/logger';
11
+ import ThrowableDiagnostic, {errorToDiagnostic} from '@atlaspack/diagnostic';
12
+ import AtlaspackConfig from './AtlaspackConfig';
13
+ import UncommittedAsset from './UncommittedAsset';
14
+ import {createAsset} from './assetUtils';
15
+ import {Asset} from './public/Asset';
16
+ import PluginOptions from './public/PluginOptions';
17
+ import summarizeRequest from './summarizeRequest';
18
+ import {fromProjectPath, fromProjectPathRelative} from './projectPath';
19
+ import {PluginTracer} from '@atlaspack/profiler';
20
+ import {hashString} from '@atlaspack/rust';
21
+
22
+ export type ValidationOpts = {|
23
+ config: AtlaspackConfig,
24
+ /**
25
+ * If true, this Validation instance will run all validators that implement the single-threaded "validateAll" method.
26
+ * If falsy, it will run validators that implement the one-asset-at-a-time "validate" method.
27
+ */
28
+ dedicatedThread?: boolean,
29
+ options: AtlaspackOptions,
30
+ requests: AssetGroup[],
31
+ report: ReportFn,
32
+ workerApi?: WorkerApi,
33
+ |};
34
+
35
+ export default class Validation {
36
+ allAssets: {[validatorName: string]: UncommittedAsset[], ...} = {};
37
+ allValidators: {[validatorName: string]: Validator, ...} = {};
38
+ dedicatedThread: boolean;
39
+ impactfulOptions: $Shape<AtlaspackOptions>;
40
+ options: AtlaspackOptions;
41
+ atlaspackConfig: AtlaspackConfig;
42
+ report: ReportFn;
43
+ requests: AssetGroup[];
44
+ workerApi: ?WorkerApi;
45
+
46
+ constructor({
47
+ config,
48
+ dedicatedThread,
49
+ options,
50
+ requests,
51
+ report,
52
+ workerApi,
53
+ }: ValidationOpts) {
54
+ this.dedicatedThread = dedicatedThread ?? false;
55
+ this.options = options;
56
+ this.atlaspackConfig = config;
57
+ this.report = report;
58
+ this.requests = requests;
59
+ this.workerApi = workerApi;
60
+ }
61
+
62
+ async run(): Promise<void> {
63
+ let pluginOptions = new PluginOptions(this.options);
64
+ await this.buildAssetsAndValidators();
65
+ await Promise.all(
66
+ Object.keys(this.allValidators).map(async validatorName => {
67
+ let assets = this.allAssets[validatorName];
68
+ if (assets) {
69
+ let plugin = this.allValidators[validatorName];
70
+ let validatorLogger = new PluginLogger({origin: validatorName});
71
+ let validatorTracer = new PluginTracer({
72
+ origin: validatorName,
73
+ category: 'validator',
74
+ });
75
+ let validatorResults: Array<?ValidateResult> = [];
76
+ try {
77
+ // If the plugin supports the single-threading validateAll method, pass all assets to it.
78
+ if (plugin.validateAll && this.dedicatedThread) {
79
+ validatorResults = await plugin.validateAll({
80
+ assets: assets.map(asset => new Asset(asset)),
81
+ options: pluginOptions,
82
+ logger: validatorLogger,
83
+ tracer: validatorTracer,
84
+ resolveConfigWithPath: (
85
+ configNames: Array<string>,
86
+ assetFilePath: string,
87
+ ) =>
88
+ resolveConfig(
89
+ this.options.inputFS,
90
+ assetFilePath,
91
+ configNames,
92
+ this.options.projectRoot,
93
+ ),
94
+ });
95
+ }
96
+
97
+ // Otherwise, pass the assets one-at-a-time
98
+ else if (plugin.validate && !this.dedicatedThread) {
99
+ await Promise.all(
100
+ assets.map(async input => {
101
+ let config = null;
102
+ let publicAsset = new Asset(input);
103
+ if (plugin.getConfig) {
104
+ config = await plugin.getConfig({
105
+ asset: publicAsset,
106
+ options: pluginOptions,
107
+ logger: validatorLogger,
108
+ tracer: validatorTracer,
109
+ resolveConfig: (configNames: Array<string>) =>
110
+ resolveConfig(
111
+ this.options.inputFS,
112
+ publicAsset.filePath,
113
+ configNames,
114
+ this.options.projectRoot,
115
+ ),
116
+ });
117
+ }
118
+
119
+ let validatorResult = await plugin.validate({
120
+ asset: publicAsset,
121
+ options: pluginOptions,
122
+ config,
123
+ logger: validatorLogger,
124
+ tracer: validatorTracer,
125
+ });
126
+ validatorResults.push(validatorResult);
127
+ }),
128
+ );
129
+ }
130
+ this.handleResults(validatorResults);
131
+ } catch (e) {
132
+ throw new ThrowableDiagnostic({
133
+ diagnostic: errorToDiagnostic(e, {
134
+ origin: validatorName,
135
+ }),
136
+ });
137
+ }
138
+ }
139
+ }),
140
+ );
141
+ }
142
+
143
+ async buildAssetsAndValidators() {
144
+ // Figure out what validators need to be run, and group the assets by the relevant validators.
145
+ await Promise.all(
146
+ this.requests.map(async request => {
147
+ this.report({
148
+ type: 'validation',
149
+ filePath: fromProjectPath(this.options.projectRoot, request.filePath),
150
+ });
151
+
152
+ let asset = await this.loadAsset(request);
153
+
154
+ let validators = await this.atlaspackConfig.getValidators(
155
+ request.filePath,
156
+ );
157
+
158
+ for (let validator of validators) {
159
+ this.allValidators[validator.name] = validator.plugin;
160
+ if (this.allAssets[validator.name]) {
161
+ this.allAssets[validator.name].push(asset);
162
+ } else {
163
+ this.allAssets[validator.name] = [asset];
164
+ }
165
+ }
166
+ }),
167
+ );
168
+ }
169
+
170
+ handleResults(validatorResults: Array<?ValidateResult>) {
171
+ let warnings: Array<Diagnostic> = [];
172
+ let errors: Array<Diagnostic> = [];
173
+ validatorResults.forEach(result => {
174
+ if (result) {
175
+ warnings.push(...result.warnings);
176
+ errors.push(...result.errors);
177
+ }
178
+ });
179
+
180
+ if (errors.length > 0) {
181
+ throw new ThrowableDiagnostic({
182
+ diagnostic: errors,
183
+ });
184
+ }
185
+
186
+ if (warnings.length > 0) {
187
+ logger.warn(warnings);
188
+ }
189
+ }
190
+
191
+ async loadAsset(request: AssetGroup): Promise<UncommittedAsset> {
192
+ let {filePath, env, code, sideEffects, query} = request;
193
+ let {content, size, isSource} = await summarizeRequest(
194
+ this.options.inputFS,
195
+ {
196
+ filePath: fromProjectPath(this.options.projectRoot, request.filePath),
197
+ },
198
+ );
199
+
200
+ // If the transformer request passed code rather than a filename,
201
+ // use a hash as the base for the id to ensure it is unique.
202
+ let idBase =
203
+ code != null ? hashString(code) : fromProjectPathRelative(filePath);
204
+ return new UncommittedAsset({
205
+ idBase,
206
+ value: createAsset(this.options.projectRoot, {
207
+ idBase,
208
+ filePath: filePath,
209
+ isSource,
210
+ type: path.extname(fromProjectPathRelative(filePath)).slice(1),
211
+ query,
212
+ env: env,
213
+ stats: {
214
+ time: 0,
215
+ size,
216
+ },
217
+ sideEffects: sideEffects,
218
+ }),
219
+ options: this.options,
220
+ content,
221
+ });
222
+ }
223
+ }