@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,1089 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.RequestGraph = void 0;
7
+ exports.getWatcherOptions = getWatcherOptions;
8
+ exports.readAndDeserializeRequestGraph = readAndDeserializeRequestGraph;
9
+ exports.requestTypes = exports.requestGraphEdgeTypes = void 0;
10
+ function _assert() {
11
+ const data = _interopRequireWildcard(require("assert"));
12
+ _assert = function () {
13
+ return data;
14
+ };
15
+ return data;
16
+ }
17
+ function _path2() {
18
+ const data = _interopRequireDefault(require("path"));
19
+ _path2 = function () {
20
+ return data;
21
+ };
22
+ return data;
23
+ }
24
+ function _graph() {
25
+ const data = require("@atlaspack/graph");
26
+ _graph = function () {
27
+ return data;
28
+ };
29
+ return data;
30
+ }
31
+ function _logger() {
32
+ const data = _interopRequireDefault(require("@atlaspack/logger"));
33
+ _logger = function () {
34
+ return data;
35
+ };
36
+ return data;
37
+ }
38
+ function _rust() {
39
+ const data = require("@atlaspack/rust");
40
+ _rust = function () {
41
+ return data;
42
+ };
43
+ return data;
44
+ }
45
+ function _utils() {
46
+ const data = require("@atlaspack/utils");
47
+ _utils = function () {
48
+ return data;
49
+ };
50
+ return data;
51
+ }
52
+ function _nullthrows() {
53
+ const data = _interopRequireDefault(require("nullthrows"));
54
+ _nullthrows = function () {
55
+ return data;
56
+ };
57
+ return data;
58
+ }
59
+ var _constants = require("./constants");
60
+ var _projectPath = require("./projectPath");
61
+ var _ReporterRunner = require("./ReporterRunner");
62
+ var _ConfigRequest = require("./requests/ConfigRequest");
63
+ var _serializer = require("./serializer");
64
+ var _utils2 = require("./utils");
65
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
66
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
67
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
68
+ const requestGraphEdgeTypes = exports.requestGraphEdgeTypes = {
69
+ subrequest: 2,
70
+ invalidated_by_update: 3,
71
+ invalidated_by_delete: 4,
72
+ invalidated_by_create: 5,
73
+ invalidated_by_create_above: 6,
74
+ dirname: 7
75
+ };
76
+ class FSBailoutError extends Error {
77
+ name = 'FSBailoutError';
78
+ }
79
+ const FILE = 0;
80
+ const REQUEST = 1;
81
+ const FILE_NAME = 2;
82
+ const ENV = 3;
83
+ const OPTION = 4;
84
+ const GLOB = 5;
85
+ const CONFIG_KEY = 6;
86
+ const requestTypes = exports.requestTypes = {
87
+ atlaspack_build_request: 1,
88
+ bundle_graph_request: 2,
89
+ asset_graph_request: 3,
90
+ entry_request: 4,
91
+ target_request: 5,
92
+ atlaspack_config_request: 6,
93
+ path_request: 7,
94
+ dev_dep_request: 8,
95
+ asset_request: 9,
96
+ config_request: 10,
97
+ write_bundles_request: 11,
98
+ package_request: 12,
99
+ write_bundle_request: 13,
100
+ validation_request: 14
101
+ };
102
+ const nodeFromFilePath = filePath => ({
103
+ id: (0, _projectPath.fromProjectPathRelative)(filePath),
104
+ type: FILE
105
+ });
106
+ const nodeFromGlob = glob => ({
107
+ id: (0, _projectPath.fromProjectPathRelative)(glob),
108
+ type: GLOB,
109
+ value: glob
110
+ });
111
+ const nodeFromFileName = fileName => ({
112
+ id: 'file_name:' + fileName,
113
+ type: FILE_NAME
114
+ });
115
+ const nodeFromRequest = request => ({
116
+ id: request.id,
117
+ type: REQUEST,
118
+ requestType: request.requestType,
119
+ invalidateReason: _constants.INITIAL_BUILD
120
+ });
121
+ const nodeFromEnv = (env, value) => ({
122
+ id: 'env:' + env,
123
+ type: ENV,
124
+ value
125
+ });
126
+ const nodeFromOption = (option, value) => ({
127
+ id: 'option:' + option,
128
+ type: OPTION,
129
+ hash: (0, _utils2.hashFromOption)(value)
130
+ });
131
+ const nodeFromConfigKey = (fileName, configKey, contentHash) => ({
132
+ id: `config_key:${(0, _projectPath.fromProjectPathRelative)(fileName)}:${configKey}`,
133
+ type: CONFIG_KEY,
134
+ configKey,
135
+ contentHash
136
+ });
137
+ const keyFromEnvContentKey = contentKey => contentKey.slice('env:'.length);
138
+ const keyFromOptionContentKey = contentKey => contentKey.slice('option:'.length);
139
+
140
+ // This constant is chosen by local profiling the time to serialise n nodes and tuning until an average time of ~50 ms per blob.
141
+ // The goal is to free up the event loop periodically to allow interruption by the user.
142
+ const NODES_PER_BLOB = 2 ** 14;
143
+ class RequestGraph extends _graph().ContentGraph {
144
+ invalidNodeIds = new Set();
145
+ incompleteNodeIds = new Set();
146
+ incompleteNodePromises = new Map();
147
+ globNodeIds = new Set();
148
+ envNodeIds = new Set();
149
+ optionNodeIds = new Set();
150
+ // Unpredictable nodes are requests that cannot be predicted whether they should rerun based on
151
+ // filesystem changes alone. They should rerun on each startup of Atlaspack.
152
+ unpredicatableNodeIds = new Set();
153
+ invalidateOnBuildNodeIds = new Set();
154
+ cachedRequestChunks = new Set();
155
+ configKeyNodes = new Map();
156
+ nodesPerBlob = NODES_PER_BLOB;
157
+
158
+ // $FlowFixMe[prop-missing]
159
+ static deserialize(opts) {
160
+ // $FlowFixMe[prop-missing]
161
+ let deserialized = new RequestGraph(opts);
162
+ deserialized.invalidNodeIds = opts.invalidNodeIds;
163
+ deserialized.incompleteNodeIds = opts.incompleteNodeIds;
164
+ deserialized.globNodeIds = opts.globNodeIds;
165
+ deserialized.envNodeIds = opts.envNodeIds;
166
+ deserialized.optionNodeIds = opts.optionNodeIds;
167
+ deserialized.unpredicatableNodeIds = opts.unpredicatableNodeIds;
168
+ deserialized.invalidateOnBuildNodeIds = opts.invalidateOnBuildNodeIds;
169
+ deserialized.cachedRequestChunks = opts.cachedRequestChunks;
170
+ deserialized.configKeyNodes = opts.configKeyNodes;
171
+ return deserialized;
172
+ }
173
+
174
+ // $FlowFixMe[prop-missing]
175
+ serialize() {
176
+ return {
177
+ ...super.serialize(),
178
+ invalidNodeIds: this.invalidNodeIds,
179
+ incompleteNodeIds: this.incompleteNodeIds,
180
+ globNodeIds: this.globNodeIds,
181
+ envNodeIds: this.envNodeIds,
182
+ optionNodeIds: this.optionNodeIds,
183
+ unpredicatableNodeIds: this.unpredicatableNodeIds,
184
+ invalidateOnBuildNodeIds: this.invalidateOnBuildNodeIds,
185
+ cachedRequestChunks: this.cachedRequestChunks,
186
+ configKeyNodes: this.configKeyNodes
187
+ };
188
+ }
189
+
190
+ // addNode for RequestGraph should not override the value if added multiple times
191
+ addNode(node) {
192
+ let nodeId = this._contentKeyToNodeId.get(node.id);
193
+ if (nodeId != null) {
194
+ return nodeId;
195
+ }
196
+ nodeId = super.addNodeByContentKey(node.id, node);
197
+ if (node.type === GLOB) {
198
+ this.globNodeIds.add(nodeId);
199
+ } else if (node.type === ENV) {
200
+ this.envNodeIds.add(nodeId);
201
+ } else if (node.type === OPTION) {
202
+ this.optionNodeIds.add(nodeId);
203
+ }
204
+ this.removeCachedRequestChunkForNode(nodeId);
205
+ return nodeId;
206
+ }
207
+ removeNode(nodeId) {
208
+ this.invalidNodeIds.delete(nodeId);
209
+ this.incompleteNodeIds.delete(nodeId);
210
+ this.incompleteNodePromises.delete(nodeId);
211
+ this.unpredicatableNodeIds.delete(nodeId);
212
+ this.invalidateOnBuildNodeIds.delete(nodeId);
213
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
214
+ if (node.type === GLOB) {
215
+ this.globNodeIds.delete(nodeId);
216
+ } else if (node.type === ENV) {
217
+ this.envNodeIds.delete(nodeId);
218
+ } else if (node.type === OPTION) {
219
+ this.optionNodeIds.delete(nodeId);
220
+ } else if (node.type === CONFIG_KEY) {
221
+ for (let configKeyNodes of this.configKeyNodes.values()) {
222
+ configKeyNodes.delete(nodeId);
223
+ }
224
+ }
225
+ return super.removeNode(nodeId);
226
+ }
227
+ getRequestNode(nodeId) {
228
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
229
+ if (node.type === REQUEST) {
230
+ return node;
231
+ }
232
+ throw new (_assert().AssertionError)({
233
+ message: `Expected a request node: ${node.type} (${typeof node.type}) does not equal ${REQUEST} (${typeof REQUEST}).`,
234
+ expected: REQUEST,
235
+ actual: node.type
236
+ });
237
+ }
238
+ replaceSubrequests(requestNodeId, subrequestContentKeys) {
239
+ let subrequestNodeIds = [];
240
+ for (let key of subrequestContentKeys) {
241
+ if (this.hasContentKey(key)) {
242
+ subrequestNodeIds.push(this.getNodeIdByContentKey(key));
243
+ }
244
+ }
245
+ this.replaceNodeIdsConnectedTo(requestNodeId, subrequestNodeIds, null, requestGraphEdgeTypes.subrequest);
246
+ }
247
+ invalidateNode(nodeId, reason) {
248
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
249
+ (0, _assert().default)(node.type === REQUEST);
250
+ node.invalidateReason |= reason;
251
+ this.invalidNodeIds.add(nodeId);
252
+ let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.subrequest);
253
+ for (let parentNode of parentNodes) {
254
+ this.invalidateNode(parentNode, reason);
255
+ }
256
+
257
+ // If the node is invalidated, the cached request chunk on disk needs to be re-written
258
+ this.removeCachedRequestChunkForNode(nodeId);
259
+ }
260
+ invalidateUnpredictableNodes() {
261
+ for (let nodeId of this.unpredicatableNodeIds) {
262
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
263
+ (0, _assert().default)(node.type !== FILE && node.type !== GLOB);
264
+ this.invalidateNode(nodeId, _constants.STARTUP);
265
+ }
266
+ }
267
+ invalidateOnBuildNodes() {
268
+ for (let nodeId of this.invalidateOnBuildNodeIds) {
269
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
270
+ (0, _assert().default)(node.type !== FILE && node.type !== GLOB);
271
+ this.invalidateNode(nodeId, _constants.STARTUP);
272
+ }
273
+ }
274
+ invalidateEnvNodes(env) {
275
+ for (let nodeId of this.envNodeIds) {
276
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
277
+ (0, _assert().default)(node.type === ENV);
278
+ if (env[keyFromEnvContentKey(node.id)] !== node.value) {
279
+ let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
280
+ for (let parentNode of parentNodes) {
281
+ this.invalidateNode(parentNode, _constants.ENV_CHANGE);
282
+ }
283
+ }
284
+ }
285
+ }
286
+ invalidateOptionNodes(options) {
287
+ for (let nodeId of this.optionNodeIds) {
288
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
289
+ (0, _assert().default)(node.type === OPTION);
290
+ if ((0, _utils2.hashFromOption)(options[keyFromOptionContentKey(node.id)]) !== node.hash) {
291
+ let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
292
+ for (let parentNode of parentNodes) {
293
+ this.invalidateNode(parentNode, _constants.OPTION_CHANGE);
294
+ }
295
+ }
296
+ }
297
+ }
298
+ invalidateOnConfigKeyChange(requestNodeId, filePath, configKey, contentHash) {
299
+ let configKeyNodeId = this.addNode(nodeFromConfigKey(filePath, configKey, contentHash));
300
+ let nodes = this.configKeyNodes.get(filePath);
301
+ if (!nodes) {
302
+ nodes = new Set();
303
+ this.configKeyNodes.set(filePath, nodes);
304
+ }
305
+ nodes.add(configKeyNodeId);
306
+ if (!this.hasEdge(requestNodeId, configKeyNodeId, requestGraphEdgeTypes.invalidated_by_update)) {
307
+ this.addEdge(requestNodeId, configKeyNodeId,
308
+ // Store as an update edge, but file deletes are handled too
309
+ requestGraphEdgeTypes.invalidated_by_update);
310
+ }
311
+ }
312
+ invalidateOnFileUpdate(requestNodeId, filePath) {
313
+ let fileNodeId = this.addNode(nodeFromFilePath(filePath));
314
+ if (!this.hasEdge(requestNodeId, fileNodeId, requestGraphEdgeTypes.invalidated_by_update)) {
315
+ this.addEdge(requestNodeId, fileNodeId, requestGraphEdgeTypes.invalidated_by_update);
316
+ }
317
+ }
318
+ invalidateOnFileDelete(requestNodeId, filePath) {
319
+ let fileNodeId = this.addNode(nodeFromFilePath(filePath));
320
+ if (!this.hasEdge(requestNodeId, fileNodeId, requestGraphEdgeTypes.invalidated_by_delete)) {
321
+ this.addEdge(requestNodeId, fileNodeId, requestGraphEdgeTypes.invalidated_by_delete);
322
+ }
323
+ }
324
+ invalidateOnFileCreate(requestNodeId, input) {
325
+ let node;
326
+ if (input.glob != null) {
327
+ node = nodeFromGlob(input.glob);
328
+ } else if (input.fileName != null && input.aboveFilePath != null) {
329
+ let aboveFilePath = input.aboveFilePath;
330
+
331
+ // Create nodes and edges for each part of the filename pattern.
332
+ // For example, 'node_modules/foo' would create two nodes and one edge.
333
+ // This creates a sort of trie structure within the graph that can be
334
+ // quickly matched by following the edges. This is also memory efficient
335
+ // since common sub-paths (e.g. 'node_modules') are deduplicated.
336
+ let parts = input.fileName.split('/').reverse();
337
+ let lastNodeId;
338
+ for (let part of parts) {
339
+ let fileNameNode = nodeFromFileName(part);
340
+ let fileNameNodeId = this.addNode(fileNameNode);
341
+ if (lastNodeId != null && !this.hasEdge(lastNodeId, fileNameNodeId, requestGraphEdgeTypes.dirname)) {
342
+ this.addEdge(lastNodeId, fileNameNodeId, requestGraphEdgeTypes.dirname);
343
+ }
344
+ lastNodeId = fileNameNodeId;
345
+ }
346
+
347
+ // The `aboveFilePath` condition asserts that requests are only invalidated
348
+ // if the file being created is "above" it in the filesystem (e.g. the file
349
+ // is created in a parent directory). There is likely to already be a node
350
+ // for this file in the graph (e.g. the source file) that we can reuse for this.
351
+ node = nodeFromFilePath(aboveFilePath);
352
+ let nodeId = this.addNode(node);
353
+
354
+ // Now create an edge from the `aboveFilePath` node to the first file_name node
355
+ // in the chain created above, and an edge from the last node in the chain back to
356
+ // the `aboveFilePath` node. When matching, we will start from the first node in
357
+ // the chain, and continue following it to parent directories until there is an
358
+ // edge pointing an `aboveFilePath` node that also points to the start of the chain.
359
+ // This indicates a complete match, and any requests attached to the `aboveFilePath`
360
+ // node will be invalidated.
361
+ let firstId = 'file_name:' + parts[0];
362
+ let firstNodeId = this.getNodeIdByContentKey(firstId);
363
+ if (!this.hasEdge(nodeId, firstNodeId, requestGraphEdgeTypes.invalidated_by_create_above)) {
364
+ this.addEdge(nodeId, firstNodeId, requestGraphEdgeTypes.invalidated_by_create_above);
365
+ }
366
+ (0, _assert().default)(lastNodeId != null);
367
+ if (!this.hasEdge(lastNodeId, nodeId, requestGraphEdgeTypes.invalidated_by_create_above)) {
368
+ this.addEdge(lastNodeId, nodeId, requestGraphEdgeTypes.invalidated_by_create_above);
369
+ }
370
+ } else if (input.filePath != null) {
371
+ node = nodeFromFilePath(input.filePath);
372
+ } else {
373
+ throw new Error('Invalid invalidation');
374
+ }
375
+ let nodeId = this.addNode(node);
376
+ if (!this.hasEdge(requestNodeId, nodeId, requestGraphEdgeTypes.invalidated_by_create)) {
377
+ this.addEdge(requestNodeId, nodeId, requestGraphEdgeTypes.invalidated_by_create);
378
+ }
379
+ }
380
+ invalidateOnStartup(requestNodeId) {
381
+ this.getRequestNode(requestNodeId);
382
+ this.unpredicatableNodeIds.add(requestNodeId);
383
+ }
384
+ invalidateOnBuild(requestNodeId) {
385
+ this.getRequestNode(requestNodeId);
386
+ this.invalidateOnBuildNodeIds.add(requestNodeId);
387
+ }
388
+ invalidateOnEnvChange(requestNodeId, env, value) {
389
+ let envNode = nodeFromEnv(env, value);
390
+ let envNodeId = this.addNode(envNode);
391
+ if (!this.hasEdge(requestNodeId, envNodeId, requestGraphEdgeTypes.invalidated_by_update)) {
392
+ this.addEdge(requestNodeId, envNodeId, requestGraphEdgeTypes.invalidated_by_update);
393
+ }
394
+ }
395
+ invalidateOnOptionChange(requestNodeId, option, value) {
396
+ let optionNode = nodeFromOption(option, value);
397
+ let optionNodeId = this.addNode(optionNode);
398
+ if (!this.hasEdge(requestNodeId, optionNodeId, requestGraphEdgeTypes.invalidated_by_update)) {
399
+ this.addEdge(requestNodeId, optionNodeId, requestGraphEdgeTypes.invalidated_by_update);
400
+ }
401
+ }
402
+ clearInvalidations(nodeId) {
403
+ this.unpredicatableNodeIds.delete(nodeId);
404
+ this.invalidateOnBuildNodeIds.delete(nodeId);
405
+ this.replaceNodeIdsConnectedTo(nodeId, [], null, requestGraphEdgeTypes.invalidated_by_update);
406
+ this.replaceNodeIdsConnectedTo(nodeId, [], null, requestGraphEdgeTypes.invalidated_by_delete);
407
+ this.replaceNodeIdsConnectedTo(nodeId, [], null, requestGraphEdgeTypes.invalidated_by_create);
408
+ }
409
+ getInvalidations(requestNodeId) {
410
+ if (!this.hasNode(requestNodeId)) {
411
+ return [];
412
+ }
413
+
414
+ // For now just handling updates. Could add creates/deletes later if needed.
415
+ let invalidations = this.getNodeIdsConnectedFrom(requestNodeId, requestGraphEdgeTypes.invalidated_by_update);
416
+ return invalidations.map(nodeId => {
417
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
418
+ switch (node.type) {
419
+ case FILE:
420
+ return {
421
+ type: 'file',
422
+ filePath: (0, _projectPath.toProjectPathUnsafe)(node.id)
423
+ };
424
+ case ENV:
425
+ return {
426
+ type: 'env',
427
+ key: keyFromEnvContentKey(node.id)
428
+ };
429
+ case OPTION:
430
+ return {
431
+ type: 'option',
432
+ key: keyFromOptionContentKey(node.id)
433
+ };
434
+ }
435
+ }).filter(Boolean);
436
+ }
437
+ getSubRequests(requestNodeId) {
438
+ if (!this.hasNode(requestNodeId)) {
439
+ return [];
440
+ }
441
+ let subRequests = this.getNodeIdsConnectedFrom(requestNodeId, requestGraphEdgeTypes.subrequest);
442
+ return subRequests.map(nodeId => {
443
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
444
+ (0, _assert().default)(node.type === REQUEST);
445
+ return node;
446
+ });
447
+ }
448
+ getInvalidSubRequests(requestNodeId) {
449
+ if (!this.hasNode(requestNodeId)) {
450
+ return [];
451
+ }
452
+ let subRequests = this.getNodeIdsConnectedFrom(requestNodeId, requestGraphEdgeTypes.subrequest);
453
+ return subRequests.filter(id => this.invalidNodeIds.has(id)).map(nodeId => {
454
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
455
+ (0, _assert().default)(node.type === REQUEST);
456
+ return node;
457
+ });
458
+ }
459
+ invalidateFileNameNode(node, filePath, matchNodes) {
460
+ // If there is an edge between this file_name node and one of the original file nodes pointed to
461
+ // by the original file_name node, and the matched node is inside the current directory, invalidate
462
+ // all connected requests pointed to by the file node.
463
+ let dirname = _path2().default.dirname((0, _projectPath.fromProjectPathRelative)(filePath));
464
+ let nodeId = this.getNodeIdByContentKey(node.id);
465
+ for (let matchNode of matchNodes) {
466
+ let matchNodeId = this.getNodeIdByContentKey(matchNode.id);
467
+ if (this.hasEdge(nodeId, matchNodeId, requestGraphEdgeTypes.invalidated_by_create_above) && (0, _utils().isDirectoryInside)((0, _projectPath.fromProjectPathRelative)((0, _projectPath.toProjectPathUnsafe)(matchNode.id)), dirname)) {
468
+ let connectedNodes = this.getNodeIdsConnectedTo(matchNodeId, requestGraphEdgeTypes.invalidated_by_create);
469
+ for (let connectedNode of connectedNodes) {
470
+ this.invalidateNode(connectedNode, _constants.FILE_CREATE);
471
+ }
472
+ }
473
+ }
474
+
475
+ // Find the `file_name` node for the parent directory and
476
+ // recursively invalidate connected requests as described above.
477
+ let basename = _path2().default.basename(dirname);
478
+ let contentKey = 'file_name:' + basename;
479
+ if (this.hasContentKey(contentKey)) {
480
+ if (this.hasEdge(nodeId, this.getNodeIdByContentKey(contentKey), requestGraphEdgeTypes.dirname)) {
481
+ let parent = (0, _nullthrows().default)(this.getNodeByContentKey(contentKey));
482
+ (0, _assert().default)(parent.type === FILE_NAME);
483
+ this.invalidateFileNameNode(parent, (0, _projectPath.toProjectPathUnsafe)(dirname), matchNodes);
484
+ }
485
+ }
486
+ }
487
+ async respondToFSEvents(events, options, threshold) {
488
+ let didInvalidate = false;
489
+ let count = 0;
490
+ let predictedTime = 0;
491
+ let startTime = Date.now();
492
+ for (let {
493
+ path: _path,
494
+ type
495
+ } of events) {
496
+ if (++count === 256) {
497
+ let duration = Date.now() - startTime;
498
+ predictedTime = duration * (events.length >> 8);
499
+ if (predictedTime > threshold) {
500
+ _logger().default.warn({
501
+ origin: '@atlaspack/core',
502
+ message: 'Building with clean cache. Cache invalidation took too long.',
503
+ meta: {
504
+ trackableEvent: 'cache_invalidation_timeout',
505
+ watcherEventCount: events.length,
506
+ predictedTime
507
+ }
508
+ });
509
+ throw new FSBailoutError('Responding to file system events exceeded threshold, start with empty cache.');
510
+ }
511
+ }
512
+ let _filePath = (0, _projectPath.toProjectPath)(options.projectRoot, _path);
513
+ let filePath = (0, _projectPath.fromProjectPathRelative)(_filePath);
514
+ let hasFileRequest = this.hasContentKey(filePath);
515
+
516
+ // If we see a 'create' event for the project root itself,
517
+ // this means the project root was moved and we need to
518
+ // re-run all requests.
519
+ if (type === 'create' && filePath === '') {
520
+ _logger().default.verbose({
521
+ origin: '@atlaspack/core',
522
+ message: 'Watcher reported project root create event. Invalidate all nodes.',
523
+ meta: {
524
+ trackableEvent: 'project_root_create'
525
+ }
526
+ });
527
+ for (let [id, node] of this.nodes.entries()) {
528
+ if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST) {
529
+ this.invalidNodeIds.add(id);
530
+ }
531
+ }
532
+ return true;
533
+ }
534
+
535
+ // sometimes mac os reports update events as create events.
536
+ // if it was a create event, but the file already exists in the graph,
537
+ // then also invalidate nodes connected by invalidated_by_update edges.
538
+ if (hasFileRequest && (type === 'create' || type === 'update')) {
539
+ let nodeId = this.getNodeIdByContentKey(filePath);
540
+ let nodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
541
+ for (let connectedNode of nodes) {
542
+ didInvalidate = true;
543
+ this.invalidateNode(connectedNode, _constants.FILE_UPDATE);
544
+ }
545
+ if (type === 'create') {
546
+ let nodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_create);
547
+ for (let connectedNode of nodes) {
548
+ didInvalidate = true;
549
+ this.invalidateNode(connectedNode, _constants.FILE_CREATE);
550
+ }
551
+ }
552
+ } else if (type === 'create') {
553
+ let basename = _path2().default.basename(filePath);
554
+ let fileNameNode = this.getNodeByContentKey('file_name:' + basename);
555
+ if (fileNameNode != null && fileNameNode.type === FILE_NAME) {
556
+ let fileNameNodeId = this.getNodeIdByContentKey('file_name:' + basename);
557
+
558
+ // Find potential file nodes to be invalidated if this file name pattern matches
559
+ let above = [];
560
+ for (const nodeId of this.getNodeIdsConnectedTo(fileNameNodeId, requestGraphEdgeTypes.invalidated_by_create_above)) {
561
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
562
+ // these might also be `glob` nodes which get handled below, we only care about files here.
563
+ if (node.type === FILE) {
564
+ above.push(node);
565
+ }
566
+ }
567
+ if (above.length > 0) {
568
+ didInvalidate = true;
569
+ this.invalidateFileNameNode(fileNameNode, _filePath, above);
570
+ }
571
+ }
572
+ for (let globeNodeId of this.globNodeIds) {
573
+ let globNode = this.getNode(globeNodeId);
574
+ (0, _assert().default)(globNode && globNode.type === GLOB);
575
+ if ((0, _utils().isGlobMatch)(filePath, (0, _projectPath.fromProjectPathRelative)(globNode.value))) {
576
+ let connectedNodes = this.getNodeIdsConnectedTo(globeNodeId, requestGraphEdgeTypes.invalidated_by_create);
577
+ for (let connectedNode of connectedNodes) {
578
+ didInvalidate = true;
579
+ this.invalidateNode(connectedNode, _constants.FILE_CREATE);
580
+ }
581
+ }
582
+ }
583
+ } else if (hasFileRequest && type === 'delete') {
584
+ let nodeId = this.getNodeIdByContentKey(filePath);
585
+ for (let connectedNode of this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_delete)) {
586
+ didInvalidate = true;
587
+ this.invalidateNode(connectedNode, _constants.FILE_DELETE);
588
+ }
589
+
590
+ // Delete the file node since it doesn't exist anymore.
591
+ // This ensures that files that don't exist aren't sent
592
+ // to requests as invalidations for future requests.
593
+ this.removeNode(nodeId);
594
+ }
595
+ let configKeyNodes = this.configKeyNodes.get(_filePath);
596
+ if (configKeyNodes && (type === 'delete' || type === 'update')) {
597
+ for (let nodeId of configKeyNodes) {
598
+ let isInvalid = type === 'delete';
599
+ if (type === 'update') {
600
+ let node = this.getNode(nodeId);
601
+ (0, _assert().default)(node && node.type === CONFIG_KEY);
602
+ let contentHash = await (0, _ConfigRequest.getConfigKeyContentHash)(_filePath, node.configKey, options);
603
+ isInvalid = node.contentHash !== contentHash;
604
+ }
605
+ if (isInvalid) {
606
+ for (let connectedNode of this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update)) {
607
+ this.invalidateNode(connectedNode, type === 'delete' ? _constants.FILE_DELETE : _constants.FILE_UPDATE);
608
+ }
609
+ didInvalidate = true;
610
+ this.removeNode(nodeId);
611
+ }
612
+ }
613
+ }
614
+ }
615
+ let duration = Date.now() - startTime;
616
+ _logger().default.verbose({
617
+ origin: '@atlaspack/core',
618
+ message: `RequestGraph.respondToFSEvents duration: ${duration}`,
619
+ meta: {
620
+ trackableEvent: 'fsevent_response_time',
621
+ duration,
622
+ predictedTime
623
+ }
624
+ });
625
+ return didInvalidate && this.invalidNodeIds.size > 0;
626
+ }
627
+ hasCachedRequestChunk(index) {
628
+ return this.cachedRequestChunks.has(index);
629
+ }
630
+ setCachedRequestChunk(index) {
631
+ this.cachedRequestChunks.add(index);
632
+ }
633
+ removeCachedRequestChunkForNode(nodeId) {
634
+ this.cachedRequestChunks.delete(Math.floor(nodeId / this.nodesPerBlob));
635
+ }
636
+ }
637
+ exports.RequestGraph = RequestGraph;
638
+ class RequestTracker {
639
+ stats = new Map();
640
+ constructor({
641
+ graph,
642
+ farm,
643
+ options,
644
+ rustAtlaspack
645
+ }) {
646
+ this.graph = graph || new RequestGraph();
647
+ this.farm = farm;
648
+ this.options = options;
649
+ this.rustAtlaspack = rustAtlaspack;
650
+ }
651
+
652
+ // TODO: refactor (abortcontroller should be created by RequestTracker)
653
+ setSignal(signal) {
654
+ this.signal = signal;
655
+ }
656
+ startRequest(request) {
657
+ let didPreviouslyExist = this.graph.hasContentKey(request.id);
658
+ let requestNodeId;
659
+ if (didPreviouslyExist) {
660
+ requestNodeId = this.graph.getNodeIdByContentKey(request.id);
661
+ // Clear existing invalidations for the request so that the new
662
+ // invalidations created during the request replace the existing ones.
663
+ this.graph.clearInvalidations(requestNodeId);
664
+ } else {
665
+ requestNodeId = this.graph.addNode(nodeFromRequest(request));
666
+ }
667
+ this.graph.incompleteNodeIds.add(requestNodeId);
668
+ this.graph.invalidNodeIds.delete(requestNodeId);
669
+ let {
670
+ promise,
671
+ deferred
672
+ } = (0, _utils().makeDeferredWithPromise)();
673
+ this.graph.incompleteNodePromises.set(requestNodeId, promise);
674
+ return {
675
+ requestNodeId,
676
+ deferred
677
+ };
678
+ }
679
+
680
+ // If a cache key is provided, the result will be removed from the node and stored in a separate cache entry
681
+ storeResult(nodeId, result, cacheKey) {
682
+ let node = this.graph.getNode(nodeId);
683
+ if (node && node.type === REQUEST) {
684
+ node.result = result;
685
+ node.resultCacheKey = cacheKey;
686
+ }
687
+ }
688
+ hasValidResult(nodeId) {
689
+ return this.graph.hasNode(nodeId) && !this.graph.invalidNodeIds.has(nodeId) && !this.graph.incompleteNodeIds.has(nodeId);
690
+ }
691
+ async getRequestResult(contentKey, ifMatch) {
692
+ let node = (0, _nullthrows().default)(this.graph.getNodeByContentKey(contentKey));
693
+ (0, _assert().default)(node.type === REQUEST);
694
+ if (ifMatch != null && node.resultCacheKey !== ifMatch) {
695
+ return null;
696
+ }
697
+ if (node.result != undefined) {
698
+ // $FlowFixMe
699
+ let result = node.result;
700
+ return result;
701
+ } else if (node.resultCacheKey != null && ifMatch == null) {
702
+ let key = node.resultCacheKey;
703
+ (0, _assert().default)(this.options.cache.hasLargeBlob(key));
704
+ let cachedResult = (0, _serializer.deserialize)(await this.options.cache.getLargeBlob(key));
705
+ node.result = cachedResult;
706
+ return cachedResult;
707
+ }
708
+ }
709
+ completeRequest(nodeId) {
710
+ this.graph.invalidNodeIds.delete(nodeId);
711
+ this.graph.incompleteNodeIds.delete(nodeId);
712
+ this.graph.incompleteNodePromises.delete(nodeId);
713
+ let node = this.graph.getNode(nodeId);
714
+ if (node && node.type === REQUEST) {
715
+ node.invalidateReason = _constants.VALID;
716
+ }
717
+ this.graph.removeCachedRequestChunkForNode(nodeId);
718
+ }
719
+ rejectRequest(nodeId) {
720
+ this.graph.incompleteNodeIds.delete(nodeId);
721
+ this.graph.incompleteNodePromises.delete(nodeId);
722
+ let node = this.graph.getNode(nodeId);
723
+ if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST) {
724
+ this.graph.invalidateNode(nodeId, _constants.ERROR);
725
+ }
726
+ }
727
+ respondToFSEvents(events, threshold) {
728
+ return this.graph.respondToFSEvents(events, this.options, threshold);
729
+ }
730
+ hasInvalidRequests() {
731
+ return this.graph.invalidNodeIds.size > 0;
732
+ }
733
+ getInvalidRequests() {
734
+ let invalidRequests = [];
735
+ for (let id of this.graph.invalidNodeIds) {
736
+ let node = (0, _nullthrows().default)(this.graph.getNode(id));
737
+ (0, _assert().default)(node.type === REQUEST);
738
+ invalidRequests.push(node);
739
+ }
740
+ return invalidRequests;
741
+ }
742
+ replaceSubrequests(requestNodeId, subrequestContextKeys) {
743
+ this.graph.replaceSubrequests(requestNodeId, subrequestContextKeys);
744
+ }
745
+ async runRequest(request, opts) {
746
+ let hasKey = this.graph.hasContentKey(request.id);
747
+ let requestId = hasKey ? this.graph.getNodeIdByContentKey(request.id) : undefined;
748
+ let hasValidResult = requestId != null && this.hasValidResult(requestId);
749
+ if (!(opts !== null && opts !== void 0 && opts.force) && hasValidResult) {
750
+ // $FlowFixMe[incompatible-type]
751
+ return this.getRequestResult(request.id);
752
+ }
753
+ if (requestId != null) {
754
+ let incompletePromise = this.graph.incompleteNodePromises.get(requestId);
755
+ if (incompletePromise != null) {
756
+ // There is a another instance of this request already running, wait for its completion and reuse its result
757
+ try {
758
+ if (await incompletePromise) {
759
+ // $FlowFixMe[incompatible-type]
760
+ return this.getRequestResult(request.id);
761
+ }
762
+ } catch (e) {
763
+ // Rerun this request
764
+ }
765
+ }
766
+ }
767
+ let previousInvalidations = requestId != null ? this.graph.getInvalidations(requestId) : [];
768
+ let {
769
+ requestNodeId,
770
+ deferred
771
+ } = this.startRequest({
772
+ id: request.id,
773
+ type: REQUEST,
774
+ requestType: request.type,
775
+ invalidateReason: _constants.INITIAL_BUILD
776
+ });
777
+ let {
778
+ api,
779
+ subRequestContentKeys
780
+ } = this.createAPI(requestNodeId, previousInvalidations);
781
+ try {
782
+ let node = this.graph.getRequestNode(requestNodeId);
783
+ this.stats.set(request.type, (this.stats.get(request.type) ?? 0) + 1);
784
+ let result = await request.run({
785
+ input: request.input,
786
+ api,
787
+ farm: this.farm,
788
+ invalidateReason: node.invalidateReason,
789
+ options: this.options,
790
+ rustAtlaspack: this.rustAtlaspack
791
+ });
792
+ (0, _utils2.assertSignalNotAborted)(this.signal);
793
+ this.completeRequest(requestNodeId);
794
+ deferred.resolve(true);
795
+ return result;
796
+ } catch (err) {
797
+ if (!(err instanceof _utils2.BuildAbortError) && request.type === requestTypes.dev_dep_request) {
798
+ _logger().default.verbose({
799
+ origin: '@atlaspack/core',
800
+ message: `Failed DevDepRequest`,
801
+ meta: {
802
+ trackableEvent: 'failed_dev_dep_request',
803
+ hasKey,
804
+ hasValidResult
805
+ }
806
+ });
807
+ }
808
+ this.rejectRequest(requestNodeId);
809
+ deferred.resolve(false);
810
+ throw err;
811
+ } finally {
812
+ this.graph.replaceSubrequests(requestNodeId, [...subRequestContentKeys]);
813
+ }
814
+ }
815
+ flushStats() {
816
+ let requestTypeEntries = {};
817
+ for (let key of Object.keys(requestTypes)) {
818
+ requestTypeEntries[requestTypes[key]] = key;
819
+ }
820
+ let formattedStats = {};
821
+ for (let [requestType, count] of this.stats.entries()) {
822
+ let requestTypeName = requestTypeEntries[requestType];
823
+ formattedStats[requestTypeName] = count;
824
+ }
825
+ this.stats = new Map();
826
+ return formattedStats;
827
+ }
828
+ createAPI(requestId, previousInvalidations) {
829
+ let subRequestContentKeys = new Set();
830
+ return {
831
+ api: {
832
+ invalidateOnFileCreate: input => this.graph.invalidateOnFileCreate(requestId, input),
833
+ invalidateOnConfigKeyChange: (filePath, configKey, contentHash) => this.graph.invalidateOnConfigKeyChange(requestId, filePath, configKey, contentHash),
834
+ invalidateOnFileDelete: filePath => this.graph.invalidateOnFileDelete(requestId, filePath),
835
+ invalidateOnFileUpdate: filePath => this.graph.invalidateOnFileUpdate(requestId, filePath),
836
+ invalidateOnStartup: () => this.graph.invalidateOnStartup(requestId),
837
+ invalidateOnBuild: () => this.graph.invalidateOnBuild(requestId),
838
+ invalidateOnEnvChange: env => this.graph.invalidateOnEnvChange(requestId, env, this.options.env[env]),
839
+ invalidateOnOptionChange: option => this.graph.invalidateOnOptionChange(requestId, option, this.options[option]),
840
+ getInvalidations: () => previousInvalidations,
841
+ storeResult: (result, cacheKey) => {
842
+ this.storeResult(requestId, result, cacheKey);
843
+ },
844
+ getSubRequests: () => this.graph.getSubRequests(requestId),
845
+ getInvalidSubRequests: () => this.graph.getInvalidSubRequests(requestId),
846
+ getPreviousResult: ifMatch => {
847
+ var _this$graph$getNode;
848
+ let contentKey = (0, _nullthrows().default)((_this$graph$getNode = this.graph.getNode(requestId)) === null || _this$graph$getNode === void 0 ? void 0 : _this$graph$getNode.id);
849
+ return this.getRequestResult(contentKey, ifMatch);
850
+ },
851
+ getRequestResult: id => this.getRequestResult(id),
852
+ canSkipSubrequest: contentKey => {
853
+ if (this.graph.hasContentKey(contentKey) && this.hasValidResult(this.graph.getNodeIdByContentKey(contentKey))) {
854
+ subRequestContentKeys.add(contentKey);
855
+ return true;
856
+ }
857
+ return false;
858
+ },
859
+ runRequest: (subRequest, opts) => {
860
+ subRequestContentKeys.add(subRequest.id);
861
+ return this.runRequest(subRequest, opts);
862
+ }
863
+ },
864
+ subRequestContentKeys
865
+ };
866
+ }
867
+ async writeToCache(signal) {
868
+ let cacheKey = getCacheKey(this.options);
869
+ let requestGraphKey = `requestGraph-${cacheKey}`;
870
+ if (this.options.shouldDisableCache) {
871
+ return;
872
+ }
873
+ let serialisedGraph = this.graph.serialize();
874
+
875
+ // Delete an existing request graph cache, to prevent invalid states
876
+ await this.options.cache.deleteLargeBlob(requestGraphKey);
877
+ let total = 0;
878
+ const serialiseAndSet = async (key, contents) => {
879
+ if (signal !== null && signal !== void 0 && signal.aborted) {
880
+ throw new Error('Serialization was aborted');
881
+ }
882
+ await this.options.cache.setLargeBlob(key, (0, _serializer.serialize)(contents), signal ? {
883
+ signal: signal
884
+ } : undefined);
885
+ total += 1;
886
+ (0, _ReporterRunner.report)({
887
+ type: 'cache',
888
+ phase: 'write',
889
+ total,
890
+ size: this.graph.nodes.length
891
+ });
892
+ };
893
+ let queue = new (_utils().PromiseQueue)({
894
+ maxConcurrent: 32
895
+ });
896
+ (0, _ReporterRunner.report)({
897
+ type: 'cache',
898
+ phase: 'start',
899
+ total,
900
+ size: this.graph.nodes.length
901
+ });
902
+
903
+ // Preallocating a sparse array is faster than pushing when N is high enough
904
+ let cacheableNodes = new Array(serialisedGraph.nodes.length);
905
+ for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
906
+ let node = serialisedGraph.nodes[i];
907
+ let resultCacheKey = node === null || node === void 0 ? void 0 : node.resultCacheKey;
908
+ if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST && resultCacheKey != null && (node === null || node === void 0 ? void 0 : node.result) != null) {
909
+ queue.add(() => serialiseAndSet(resultCacheKey, node.result)).catch(() => {
910
+ // Handle promise rejection
911
+ });
912
+
913
+ // eslint-disable-next-line no-unused-vars
914
+ let {
915
+ result: _,
916
+ ...newNode
917
+ } = node;
918
+ cacheableNodes[i] = newNode;
919
+ } else {
920
+ cacheableNodes[i] = node;
921
+ }
922
+ }
923
+ let nodeCountsPerBlob = [];
924
+ for (let i = 0; i * this.graph.nodesPerBlob < cacheableNodes.length; i += 1) {
925
+ let nodesStartIndex = i * this.graph.nodesPerBlob;
926
+ let nodesEndIndex = Math.min((i + 1) * this.graph.nodesPerBlob, cacheableNodes.length);
927
+ nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
928
+ if (!this.graph.hasCachedRequestChunk(i)) {
929
+ // We assume the request graph nodes are immutable and won't change
930
+ let nodesToCache = cacheableNodes.slice(nodesStartIndex, nodesEndIndex);
931
+ queue.add(() => serialiseAndSet(getRequestGraphNodeKey(i, cacheKey), nodesToCache).then(() => {
932
+ // Succeeded in writing to disk, save that we have completed this chunk
933
+ this.graph.setCachedRequestChunk(i);
934
+ })).catch(() => {
935
+ // Handle promise rejection
936
+ });
937
+ }
938
+ }
939
+ try {
940
+ await queue.run();
941
+
942
+ // Set the request graph after the queue is flushed to avoid writing an invalid state
943
+ await serialiseAndSet(requestGraphKey, {
944
+ ...serialisedGraph,
945
+ nodeCountsPerBlob,
946
+ nodes: undefined
947
+ });
948
+ let opts = getWatcherOptions(this.options);
949
+ let snapshotPath = _path2().default.join(this.options.cacheDir, `snapshot-${cacheKey}` + '.txt');
950
+ await this.options.inputFS.writeSnapshot(this.options.watchDir, snapshotPath, opts);
951
+ } catch (err) {
952
+ // If we have aborted, ignore the error and continue
953
+ if (!(signal !== null && signal !== void 0 && signal.aborted)) throw err;
954
+ }
955
+ (0, _ReporterRunner.report)({
956
+ type: 'cache',
957
+ phase: 'end',
958
+ total,
959
+ size: this.graph.nodes.length
960
+ });
961
+ }
962
+ static async init({
963
+ farm,
964
+ options,
965
+ rustAtlaspack
966
+ }) {
967
+ let graph = await loadRequestGraph(options);
968
+ return new RequestTracker({
969
+ farm,
970
+ graph,
971
+ options,
972
+ rustAtlaspack
973
+ });
974
+ }
975
+ }
976
+ exports.default = RequestTracker;
977
+ function getWatcherOptions({
978
+ watchIgnore = [],
979
+ cacheDir,
980
+ watchDir,
981
+ watchBackend
982
+ }) {
983
+ const uniqueDirs = [...new Set([...watchIgnore, ...['.git', '.hg'], cacheDir])];
984
+ const ignore = uniqueDirs.map(dir => _path2().default.resolve(watchDir, dir));
985
+ return {
986
+ ignore,
987
+ backend: watchBackend
988
+ };
989
+ }
990
+ function getCacheKey(options) {
991
+ return (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
992
+ }
993
+ function getRequestGraphNodeKey(index, cacheKey) {
994
+ return `requestGraph-nodes-${index}-${cacheKey}`;
995
+ }
996
+ async function readAndDeserializeRequestGraph(cache, requestGraphKey, cacheKey) {
997
+ let bufferLength = 0;
998
+ const getAndDeserialize = async key => {
999
+ let buffer = await cache.getLargeBlob(key);
1000
+ bufferLength += Buffer.byteLength(buffer);
1001
+ return (0, _serializer.deserialize)(buffer);
1002
+ };
1003
+ let serializedRequestGraph = await getAndDeserialize(requestGraphKey);
1004
+ let nodePromises = serializedRequestGraph.nodeCountsPerBlob.map(async (nodesCount, i) => {
1005
+ let nodes = await getAndDeserialize(getRequestGraphNodeKey(i, cacheKey));
1006
+ _assert().default.equal(nodes.length, nodesCount, 'RequestTracker node chunk: invalid node count');
1007
+ return nodes;
1008
+ });
1009
+ return {
1010
+ requestGraph: RequestGraph.deserialize({
1011
+ ...serializedRequestGraph,
1012
+ nodes: (await Promise.all(nodePromises)).flat()
1013
+ }),
1014
+ // This is used inside atlaspack query for `.inspectCache`
1015
+ bufferLength
1016
+ };
1017
+ }
1018
+ async function loadRequestGraph(options) {
1019
+ if (options.shouldDisableCache) {
1020
+ return new RequestGraph();
1021
+ }
1022
+ let cacheKey = getCacheKey(options);
1023
+ let requestGraphKey = `requestGraph-${cacheKey}`;
1024
+ let timeout;
1025
+ const snapshotPath = _path2().default.join(options.cacheDir, `snapshot-${cacheKey}` + '.txt');
1026
+ if (await options.cache.hasLargeBlob(requestGraphKey)) {
1027
+ try {
1028
+ let {
1029
+ requestGraph
1030
+ } = await readAndDeserializeRequestGraph(options.cache, requestGraphKey, cacheKey);
1031
+ let opts = getWatcherOptions(options);
1032
+ timeout = setTimeout(() => {
1033
+ _logger().default.warn({
1034
+ origin: '@atlaspack/core',
1035
+ message: `Retrieving file system events since last build...\nThis can take upto a minute after branch changes or npm/yarn installs.`
1036
+ });
1037
+ }, 5000);
1038
+ let startTime = Date.now();
1039
+ let events = await options.inputFS.getEventsSince(options.watchDir, snapshotPath, opts);
1040
+ clearTimeout(timeout);
1041
+ _logger().default.verbose({
1042
+ origin: '@atlaspack/core',
1043
+ message: `File system event count: ${events.length}`,
1044
+ meta: {
1045
+ trackableEvent: 'watcher_events_count',
1046
+ watcherEventCount: events.length,
1047
+ duration: Date.now() - startTime
1048
+ }
1049
+ });
1050
+ requestGraph.invalidateUnpredictableNodes();
1051
+ requestGraph.invalidateOnBuildNodes();
1052
+ requestGraph.invalidateEnvNodes(options.env);
1053
+ requestGraph.invalidateOptionNodes(options);
1054
+ await requestGraph.respondToFSEvents(options.unstableFileInvalidations || events, options, 10000);
1055
+ return requestGraph;
1056
+ } catch (e) {
1057
+ // Prevent logging fs events took too long warning
1058
+ clearTimeout(timeout);
1059
+ logErrorOnBailout(options, snapshotPath, e);
1060
+ // This error means respondToFSEvents timed out handling the invalidation events
1061
+ // In this case we'll return a fresh RequestGraph
1062
+ return new RequestGraph();
1063
+ }
1064
+ }
1065
+ return new RequestGraph();
1066
+ }
1067
+ function logErrorOnBailout(options, snapshotPath, e) {
1068
+ if (e.message && e.message.includes('invalid clockspec')) {
1069
+ const snapshotContents = options.inputFS.readFileSync(snapshotPath, 'utf-8');
1070
+ _logger().default.warn({
1071
+ origin: '@atlaspack/core',
1072
+ message: `Error reading clockspec from snapshot, building with clean cache.`,
1073
+ meta: {
1074
+ snapshotContents: snapshotContents,
1075
+ trackableEvent: 'invalid_clockspec_error'
1076
+ }
1077
+ });
1078
+ } else if (!(e instanceof FSBailoutError)) {
1079
+ _logger().default.warn({
1080
+ origin: '@atlaspack/core',
1081
+ message: `Unexpected error loading cache from disk, building with clean cache.`,
1082
+ meta: {
1083
+ errorMessage: e.message,
1084
+ errorStack: e.stack,
1085
+ trackableEvent: 'cache_load_error'
1086
+ }
1087
+ });
1088
+ }
1089
+ }