@teambit/isolator 0.0.0-0438888a7c5866eb047e91b207cdcc9b1a199754

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 (46) hide show
  1. package/capsule/capsule.ts +138 -0
  2. package/capsule/container-exec.ts +31 -0
  3. package/capsule/container.ts +128 -0
  4. package/capsule/index.ts +3 -0
  5. package/dist/capsule/capsule.d.ts +75 -0
  6. package/dist/capsule/capsule.js +194 -0
  7. package/dist/capsule/capsule.js.map +1 -0
  8. package/dist/capsule/container-exec.d.ts +13 -0
  9. package/dist/capsule/container-exec.js +51 -0
  10. package/dist/capsule/container-exec.js.map +1 -0
  11. package/dist/capsule/container.d.ts +34 -0
  12. package/dist/capsule/container.js +153 -0
  13. package/dist/capsule/container.js.map +1 -0
  14. package/dist/capsule/index.d.ts +3 -0
  15. package/dist/capsule/index.js +47 -0
  16. package/dist/capsule/index.js.map +1 -0
  17. package/dist/capsule-list.d.ts +22 -0
  18. package/dist/capsule-list.js +100 -0
  19. package/dist/capsule-list.js.map +1 -0
  20. package/dist/esm.mjs +13 -0
  21. package/dist/index.d.ts +6 -0
  22. package/dist/index.js +85 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/isolator.aspect.d.ts +2 -0
  25. package/dist/isolator.aspect.js +20 -0
  26. package/dist/isolator.aspect.js.map +1 -0
  27. package/dist/isolator.composition.d.ts +1 -0
  28. package/dist/isolator.composition.js +29 -0
  29. package/dist/isolator.composition.js.map +1 -0
  30. package/dist/isolator.docs.md +41 -0
  31. package/dist/isolator.main.runtime.d.ts +285 -0
  32. package/dist/isolator.main.runtime.js +1225 -0
  33. package/dist/isolator.main.runtime.js.map +1 -0
  34. package/dist/network.d.ts +131 -0
  35. package/dist/network.js +191 -0
  36. package/dist/network.js.map +1 -0
  37. package/dist/preview-1752796259513.js +7 -0
  38. package/dist/symlink-dependencies-to-capsules.d.ts +6 -0
  39. package/dist/symlink-dependencies-to-capsules.js +61 -0
  40. package/dist/symlink-dependencies-to-capsules.js.map +1 -0
  41. package/esm.mjs +13 -0
  42. package/isolator.composition.tsx +7 -0
  43. package/isolator.docs.md +41 -0
  44. package/package.json +94 -0
  45. package/types/asset.d.ts +41 -0
  46. package/types/style.d.ts +42 -0
@@ -0,0 +1,1225 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.IsolatorMain = exports.CAPSULE_READY_FILE = void 0;
7
+ function _rimraf() {
8
+ const data = _interopRequireDefault(require("rimraf"));
9
+ _rimraf = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _uuid() {
15
+ const data = require("uuid");
16
+ _uuid = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _cli() {
22
+ const data = require("@teambit/cli");
23
+ _cli = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ function _semver() {
29
+ const data = _interopRequireDefault(require("semver"));
30
+ _semver = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _chalk() {
36
+ const data = _interopRequireDefault(require("chalk"));
37
+ _chalk = function () {
38
+ return data;
39
+ };
40
+ return data;
41
+ }
42
+ function _lodash() {
43
+ const data = require("lodash");
44
+ _lodash = function () {
45
+ return data;
46
+ };
47
+ return data;
48
+ }
49
+ function _harmonyModules() {
50
+ const data = require("@teambit/harmony.modules.feature-toggle");
51
+ _harmonyModules = function () {
52
+ return data;
53
+ };
54
+ return data;
55
+ }
56
+ function _aspectLoader() {
57
+ const data = require("@teambit/aspect-loader");
58
+ _aspectLoader = function () {
59
+ return data;
60
+ };
61
+ return data;
62
+ }
63
+ function _component() {
64
+ const data = require("@teambit/component");
65
+ _component = function () {
66
+ return data;
67
+ };
68
+ return data;
69
+ }
70
+ function _componentPackageVersion() {
71
+ const data = require("@teambit/component-package-version");
72
+ _componentPackageVersion = function () {
73
+ return data;
74
+ };
75
+ return data;
76
+ }
77
+ function _dependenciesFs() {
78
+ const data = require("@teambit/dependencies.fs.linked-dependencies");
79
+ _dependenciesFs = function () {
80
+ return data;
81
+ };
82
+ return data;
83
+ }
84
+ function _graph() {
85
+ const data = require("@teambit/graph");
86
+ _graph = function () {
87
+ return data;
88
+ };
89
+ return data;
90
+ }
91
+ function _harmony() {
92
+ const data = require("@teambit/harmony");
93
+ _harmony = function () {
94
+ return data;
95
+ };
96
+ return data;
97
+ }
98
+ function _dependencyResolver() {
99
+ const data = require("@teambit/dependency-resolver");
100
+ _dependencyResolver = function () {
101
+ return data;
102
+ };
103
+ return data;
104
+ }
105
+ function _logger() {
106
+ const data = require("@teambit/logger");
107
+ _logger = function () {
108
+ return data;
109
+ };
110
+ return data;
111
+ }
112
+ function _componentId() {
113
+ const data = require("@teambit/component-id");
114
+ _componentId = function () {
115
+ return data;
116
+ };
117
+ return data;
118
+ }
119
+ function _globalConfig() {
120
+ const data = require("@teambit/global-config");
121
+ _globalConfig = function () {
122
+ return data;
123
+ };
124
+ return data;
125
+ }
126
+ function _legacy() {
127
+ const data = require("@teambit/legacy.constants");
128
+ _legacy = function () {
129
+ return data;
130
+ };
131
+ return data;
132
+ }
133
+ function _component2() {
134
+ const data = require("@teambit/component.sources");
135
+ _component2 = function () {
136
+ return data;
137
+ };
138
+ return data;
139
+ }
140
+ function _legacy2() {
141
+ const data = require("@teambit/legacy.utils");
142
+ _legacy2 = function () {
143
+ return data;
144
+ };
145
+ return data;
146
+ }
147
+ function _harmonyModules2() {
148
+ const data = require("@teambit/harmony.modules.concurrency");
149
+ _harmonyModules2 = function () {
150
+ return data;
151
+ };
152
+ return data;
153
+ }
154
+ function _pkgModules() {
155
+ const data = require("@teambit/pkg.modules.component-package-name");
156
+ _pkgModules = function () {
157
+ return data;
158
+ };
159
+ return data;
160
+ }
161
+ function _fsExtra() {
162
+ const data = _interopRequireWildcard(require("fs-extra"));
163
+ _fsExtra = function () {
164
+ return data;
165
+ };
166
+ return data;
167
+ }
168
+ function _objectHash() {
169
+ const data = _interopRequireDefault(require("object-hash"));
170
+ _objectHash = function () {
171
+ return data;
172
+ };
173
+ return data;
174
+ }
175
+ function _path() {
176
+ const data = _interopRequireWildcard(require("path"));
177
+ _path = function () {
178
+ return data;
179
+ };
180
+ return data;
181
+ }
182
+ function _workspaceModules() {
183
+ const data = require("@teambit/workspace.modules.node-modules-linker");
184
+ _workspaceModules = function () {
185
+ return data;
186
+ };
187
+ return data;
188
+ }
189
+ function _pMap() {
190
+ const data = _interopRequireDefault(require("p-map"));
191
+ _pMap = function () {
192
+ return data;
193
+ };
194
+ return data;
195
+ }
196
+ function _capsule() {
197
+ const data = require("./capsule");
198
+ _capsule = function () {
199
+ return data;
200
+ };
201
+ return data;
202
+ }
203
+ function _capsuleList() {
204
+ const data = _interopRequireDefault(require("./capsule-list"));
205
+ _capsuleList = function () {
206
+ return data;
207
+ };
208
+ return data;
209
+ }
210
+ function _isolator() {
211
+ const data = require("./isolator.aspect");
212
+ _isolator = function () {
213
+ return data;
214
+ };
215
+ return data;
216
+ }
217
+ function _symlinkDependenciesToCapsules() {
218
+ const data = require("./symlink-dependencies-to-capsules");
219
+ _symlinkDependenciesToCapsules = function () {
220
+ return data;
221
+ };
222
+ return data;
223
+ }
224
+ function _network() {
225
+ const data = require("./network");
226
+ _network = function () {
227
+ return data;
228
+ };
229
+ return data;
230
+ }
231
+ function _configStore() {
232
+ const data = require("@teambit/config-store");
233
+ _configStore = function () {
234
+ return data;
235
+ };
236
+ return data;
237
+ }
238
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
239
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
240
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
241
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
242
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
243
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
244
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
245
+ /**
246
+ * Context for the isolation process
247
+ */
248
+
249
+ /**
250
+ * it's normally a sha1 of the workspace/scope dir. 40 chars long. however, Windows is not happy with long paths.
251
+ * so we use a shorter hash. the number 9 is pretty random, it's what we use for short-hash of snaps.
252
+ * we're aware of an extremely low risk of collision. take into account that in most cases you won't have more than 10
253
+ * capsules in the machine.
254
+ */
255
+ const CAPSULE_DIR_LENGTH = 9;
256
+ const DEFAULT_ISOLATE_INSTALL_OPTIONS = {
257
+ installPackages: true,
258
+ dedupe: true,
259
+ installPeersFromEnvs: true,
260
+ copyPeerToRuntimeOnComponents: false,
261
+ copyPeerToRuntimeOnRoot: true
262
+ };
263
+
264
+ /**
265
+ * File name to indicate that the capsule is ready (all packages are installed and links are created)
266
+ */
267
+ const CAPSULE_READY_FILE = exports.CAPSULE_READY_FILE = '.bit-capsule-ready';
268
+ class IsolatorMain {
269
+ // cache moved lock files to avoid show warning about them
270
+
271
+ static async provider([dependencyResolver, loggerExtension, componentAspect, graphMain, globalConfig, aspectLoader, cli, configStore], _config, [capsuleTransferSlot]) {
272
+ const logger = loggerExtension.createLogger(_isolator().IsolatorAspect.id);
273
+ const isolator = new IsolatorMain(dependencyResolver, logger, componentAspect, graphMain, cli, globalConfig, aspectLoader, capsuleTransferSlot, configStore);
274
+ return isolator;
275
+ }
276
+ constructor(dependencyResolver, logger, componentAspect, graph, cli, globalConfig, aspectLoader, capsuleTransferSlot, configStore) {
277
+ this.dependencyResolver = dependencyResolver;
278
+ this.logger = logger;
279
+ this.componentAspect = componentAspect;
280
+ this.graph = graph;
281
+ this.cli = cli;
282
+ this.globalConfig = globalConfig;
283
+ this.aspectLoader = aspectLoader;
284
+ this.capsuleTransferSlot = capsuleTransferSlot;
285
+ this.configStore = configStore;
286
+ _defineProperty(this, "_componentsPackagesVersionCache", {});
287
+ // cache packages versions of components
288
+ _defineProperty(this, "_datedHashForName", new Map());
289
+ // cache dated hash for a specific name
290
+ _defineProperty(this, "_movedLockFiles", new Set());
291
+ }
292
+
293
+ // TODO: the legacy scope used for the component writer, which then decide if it need to write the artifacts and dists
294
+ // TODO: we should think of another way to provide it (maybe a new opts) then take the scope internally from the host
295
+ async isolateComponents(seeders, opts, legacyScope) {
296
+ const host = opts.host || this.componentAspect.getHost();
297
+ this.logger.debug(`isolateComponents, ${seeders.join(', ')}. opts: ${JSON.stringify(Object.assign({}, opts, {
298
+ host: opts.host?.name
299
+ }))}`);
300
+ const createGraphOpts = (0, _lodash().pick)(opts, ['includeFromNestedHosts', 'host']);
301
+ const componentsToIsolate = opts.seedersOnly ? await host.getMany(seeders) : await this.createGraph(seeders, createGraphOpts);
302
+ this.logger.debug(`isolateComponents, total componentsToIsolate: ${componentsToIsolate.length}`);
303
+ const seedersWithVersions = seeders.map(seeder => {
304
+ if (seeder._legacy.hasVersion()) return seeder;
305
+ const comp = componentsToIsolate.find(component => component.id.isEqual(seeder, {
306
+ ignoreVersion: true
307
+ }));
308
+ if (!comp) throw new Error(`unable to find seeder ${seeder.toString()} in componentsToIsolate`);
309
+ return comp.id;
310
+ });
311
+ opts.baseDir = opts.baseDir || host.path;
312
+ const shouldUseDatedDirs = this.shouldUseDatedDirs(componentsToIsolate, opts);
313
+ const capsuleDir = this.getCapsulesRootDir(_objectSpread(_objectSpread({}, opts), {}, {
314
+ useDatedDirs: shouldUseDatedDirs,
315
+ baseDir: opts.baseDir || ''
316
+ }));
317
+ const cacheCapsulesDir = this.getCapsulesRootDir(_objectSpread(_objectSpread({}, opts), {}, {
318
+ useDatedDirs: false,
319
+ baseDir: opts.baseDir || ''
320
+ }));
321
+ opts.cacheCapsulesDir = cacheCapsulesDir;
322
+ const capsuleList = await this.createCapsules(componentsToIsolate, capsuleDir, opts, legacyScope);
323
+ this.logger.debug(`creating network with base dir: ${opts.baseDir}, rootBaseDir: ${opts.rootBaseDir}. final capsule-dir: ${capsuleDir}. capsuleList: ${capsuleList.length}`);
324
+ const cacheCapsules = process.env.CACHE_CAPSULES || opts.cacheLockFileOnly;
325
+ if (shouldUseDatedDirs && cacheCapsules) {
326
+ const targetCapsuleDir = this.getCapsulesRootDir(_objectSpread(_objectSpread({}, opts), {}, {
327
+ useDatedDirs: false,
328
+ baseDir: opts.baseDir || ''
329
+ }));
330
+ this.registerMoveCapsuleOnProcessExit(capsuleDir, targetCapsuleDir, opts.cacheLockFileOnly);
331
+ // TODO: ideally this should be inside the on process exit hook
332
+ // but this is an async op which make it a bit hard
333
+ await this.relinkCoreAspectsInCapsuleDir(targetCapsuleDir);
334
+ }
335
+ return new (_network().Network)(capsuleList, seedersWithVersions, capsuleDir);
336
+ }
337
+ async createGraph(seeders, opts = {}) {
338
+ const host = opts.host || this.componentAspect.getHost();
339
+ const getGraphOpts = (0, _lodash().pick)(opts, ['host']);
340
+ const graph = await this.graph.getGraphIds(seeders, getGraphOpts);
341
+ const successorsSubgraph = graph.successorsSubgraph(seeders.map(id => id.toString()));
342
+ const compsAndDepsIds = successorsSubgraph.nodes.map(node => node.attr);
343
+ // do not ignore the version here. a component might be in .bitmap with one version and
344
+ // installed as a package with another version. we don't want them both.
345
+ const existingCompsIds = await Promise.all(compsAndDepsIds.map(async id => {
346
+ let existing;
347
+ if (opts.includeFromNestedHosts) {
348
+ existing = await host.hasIdNested(id, true);
349
+ } else {
350
+ existing = await host.hasId(id);
351
+ }
352
+ if (existing) return id;
353
+ return undefined;
354
+ }));
355
+ const componentsToInclude = (0, _lodash().compact)(existingCompsIds);
356
+ let filteredComps = await host.getMany(componentsToInclude);
357
+
358
+ // Optimization: exclude unmodified exported dependencies from capsule creation
359
+ if (!(0, _harmonyModules().isFeatureEnabled)(_harmonyModules().DISABLE_CAPSULE_OPTIMIZATION)) {
360
+ filteredComps = await this.filterUnmodifiedExportedDependencies(filteredComps, seeders, host);
361
+ this.logger.debug(`[OPTIMIZATION] Before filtering: ${componentsToInclude.length}. After filtering: ${filteredComps.length} components remaining`);
362
+ }
363
+ return filteredComps;
364
+ }
365
+ registerMoveCapsuleOnProcessExit(datedCapsuleDir, targetCapsuleDir, cacheLockFileOnly = false) {
366
+ this.logger.info(`registering process.on(exit) to move capsules from ${datedCapsuleDir} to ${targetCapsuleDir}`);
367
+ this.cli.registerOnBeforeExit(async () => {
368
+ const allDirs = await this.getAllCapsulesDirsFromRoot(datedCapsuleDir);
369
+ if (cacheLockFileOnly) {
370
+ await this.moveCapsulesLockFileToTargetDir(allDirs, datedCapsuleDir, targetCapsuleDir);
371
+ } else {
372
+ await this.moveCapsulesToTargetDir(allDirs, datedCapsuleDir, targetCapsuleDir);
373
+ }
374
+ });
375
+ }
376
+ async getAllCapsulesDirsFromRoot(rootDir) {
377
+ const allDirs = await _fsExtra().default.readdir(rootDir, {
378
+ withFileTypes: true
379
+ });
380
+ const capsuleDirents = allDirs.filter(dir => dir.isDirectory() && dir.name !== 'node_modules');
381
+ return capsuleDirents.map(dir => _path().default.join(rootDir, dir.name));
382
+ }
383
+ async moveCapsulesLockFileToTargetDir(capsulesDirs, sourceRootDir, targetCapsuleDir) {
384
+ this.logger.info(`start moving lock files from ${sourceRootDir} to ${targetCapsuleDir}`);
385
+ const promises = capsulesDirs.map(async sourceDir => {
386
+ const dirname = _path().default.basename(sourceDir);
387
+ const sourceLockFile = _path().default.join(sourceDir, 'pnpm-lock.yaml');
388
+ // Lock file is not exist, don't copy it to the cache
389
+ if (!_fsExtra().default.pathExistsSync(sourceLockFile)) {
390
+ // It was already moved during the process, do not show the log for it
391
+ if (!this._movedLockFiles.has(sourceLockFile)) {
392
+ this.logger.console(`skipping moving lock file to cache as it is not exist ${sourceDir}`);
393
+ }
394
+ return;
395
+ }
396
+ const targetDir = _path().default.join(targetCapsuleDir, dirname);
397
+ const targetLockFile = _path().default.join(targetDir, 'pnpm-lock.yaml');
398
+ const targetLockFileExists = await _fsExtra().default.pathExists(targetLockFile);
399
+ if (targetLockFileExists) {
400
+ // Lock file is already in the cache, no need to move it
401
+ // this.logger.console(`skipping moving lock file to cache as it is already exist at ${targetDir}`);
402
+
403
+ // Delete existing lock file so we can update it
404
+ await _fsExtra().default.remove(targetLockFile);
405
+ return;
406
+ }
407
+ this.logger.debug(`moving lock file from ${sourceLockFile} to ${targetDir}`);
408
+ const mvFunc = this.getCapsuleTransferFn();
409
+ try {
410
+ await mvFunc(sourceLockFile, _path().default.join(targetDir, 'pnpm-lock.yaml'));
411
+ this._movedLockFiles.add(sourceLockFile);
412
+ } catch (err) {
413
+ this.logger.error(`failed moving lock file from ${sourceLockFile} to ${targetDir}`, err);
414
+ }
415
+ });
416
+ await Promise.all(promises);
417
+ }
418
+ async moveCapsulesToTargetDir(capsulesDirs, sourceRootDir, targetCapsuleDir) {
419
+ this.logger.info(`start moving capsules from ${sourceRootDir} to ${targetCapsuleDir}`);
420
+ const promises = capsulesDirs.map(async sourceDir => {
421
+ const dirname = _path().default.basename(sourceDir);
422
+ const sourceCapsuleReadyFile = this.getCapsuleReadyFilePath(sourceDir);
423
+ if (!_fsExtra().default.pathExistsSync(sourceCapsuleReadyFile)) {
424
+ // Capsule is not ready, don't copy it to the cache
425
+ this.logger.console(`skipping moving capsule to cache as it is not ready ${sourceDir}`);
426
+ return;
427
+ }
428
+ const targetDir = _path().default.join(targetCapsuleDir, dirname);
429
+ if (_fsExtra().default.pathExistsSync(_path().default.join(targetCapsuleDir, dirname))) {
430
+ const targetCapsuleReadyFile = this.getCapsuleReadyFilePath(targetDir);
431
+ if (_fsExtra().default.pathExistsSync(targetCapsuleReadyFile)) {
432
+ // Capsule is already in the cache, no need to move it
433
+ this.logger.console(`skipping moving capsule to cache as it is already exist at ${targetDir}`);
434
+ return;
435
+ }
436
+ this.logger.console(`cleaning target capsule location as it's not ready at: ${targetDir}`);
437
+ _rimraf().default.sync(targetDir);
438
+ }
439
+ this.logger.console(`moving specific capsule from ${sourceDir} to ${targetDir}`);
440
+ // We delete the ready file path first, as the move might take a long time, so we don't want to move
441
+ // the ready file indicator before the capsule is ready in the new location
442
+ this.removeCapsuleReadyFileSync(sourceDir);
443
+ await this.moveWithTempName(sourceDir, targetDir, this.getCapsuleTransferFn());
444
+ // Mark the capsule as ready in the new location
445
+ this.writeCapsuleReadyFileSync(targetDir);
446
+ });
447
+ await Promise.all(promises);
448
+ }
449
+
450
+ /**
451
+ * The function moves a directory from a source location to a target location using a temporary directory.
452
+ * This is using temp dir because sometime the source dir and target dir might be in different FS
453
+ * (for example different mounts) which means the move might take a long time
454
+ * during the time of moving, another process will see that the capsule is not ready and will try to remove then
455
+ * move it again, which lead to the first process throwing an error
456
+ * @param sourceDir - The source directory from where the files or directories will be moved.
457
+ * @param targetDir - The target directory where the source directory will be moved to.
458
+ */
459
+ async moveWithTempName(sourceDir, targetDir, mvFunc = _fsExtra().default.move) {
460
+ const tempDir = `${targetDir}-${(0, _uuid().v4)()}`;
461
+ this.logger.console(`moving capsule from ${sourceDir} to a temp dir ${tempDir}`);
462
+ await mvFunc(sourceDir, tempDir);
463
+ const exists = await _fsExtra().default.pathExists(targetDir);
464
+ // This might exist if in the time when we move to the temp dir, another process created the target dir already
465
+ if (exists) {
466
+ this.logger.console(`skip moving capsule from temp dir to real dir as it's already exist: ${targetDir}`);
467
+ // Clean leftovers
468
+ await (0, _rimraf().default)(tempDir);
469
+ return;
470
+ }
471
+ this.logger.console(`moving capsule from a temp dir ${tempDir} to the target dir ${targetDir}`);
472
+ await mvFunc(tempDir, targetDir);
473
+ }
474
+
475
+ /**
476
+ * Re-create the core aspects links in the real capsule dir
477
+ * This is required mainly for the first time when that folder is empty
478
+ */
479
+ async relinkCoreAspectsInCapsuleDir(capsulesDir) {
480
+ const linkingOptions = {
481
+ linkTeambitBit: true,
482
+ linkCoreAspects: true
483
+ };
484
+ const linker = this.dependencyResolver.getLinker({
485
+ rootDir: capsulesDir,
486
+ linkingOptions,
487
+ linkingContext: {
488
+ inCapsule: true
489
+ }
490
+ });
491
+ const {
492
+ linkedRootDeps
493
+ } = await linker.calculateLinkedDeps(capsulesDir, _component().ComponentMap.create([]), linkingOptions);
494
+ // This links are in the global cache which used by many process
495
+ // we don't want to delete and re-create the links if they already exist and valid
496
+ return (0, _dependenciesFs().createLinks)(capsulesDir, linkedRootDeps, {
497
+ skipIfSymlinkValid: true
498
+ });
499
+ }
500
+ shouldUseDatedDirs(componentsToIsolate, opts) {
501
+ if (!opts.useDatedDirs) return false;
502
+ // No need to use the dated dirs in case we anyway create new capsule for each one
503
+ if (opts.alwaysNew) return false;
504
+ // if (opts.skipIfExists) return false;
505
+ // no point to use dated dir in case of getExistingAsIs as it will be just always empty
506
+ if (opts.getExistingAsIs) return false;
507
+ // Do not use the dated dirs in case we don't use nesting, as the capsules
508
+ // will not work after moving to the real dir
509
+ if (!opts.installOptions?.useNesting) return false;
510
+ // Getting the real capsule dir to check if all capsules exists
511
+ const realCapsulesDir = this.getCapsulesRootDir(_objectSpread(_objectSpread({}, opts), {}, {
512
+ useDatedDirs: false,
513
+ baseDir: opts.baseDir || ''
514
+ }));
515
+ // validate all capsules in the real location exists and valid
516
+ const allCapsulesExists = componentsToIsolate.every(component => {
517
+ const capsuleDir = _path().default.join(realCapsulesDir, _capsule().Capsule.getCapsuleDirName(component));
518
+ const readyFilePath = this.getCapsuleReadyFilePath(capsuleDir);
519
+ return _fsExtra().default.existsSync(capsuleDir) && _fsExtra().default.existsSync(readyFilePath);
520
+ });
521
+ if (allCapsulesExists) {
522
+ this.logger.debug(`All required capsules already exists and valid in the real (cached) location: ${realCapsulesDir}`);
523
+ return false;
524
+ }
525
+ this.logger.debug(`Missing required capsules in the real (cached) location: ${realCapsulesDir}, using dated (temp) dir`);
526
+ return true;
527
+ }
528
+
529
+ /**
530
+ *
531
+ * @param originalCapsule the capsule that contains the original component
532
+ * @param newBaseDir relative path. (it will be saved inside `this.getRootDirOfAllCapsules()`. the final path of the capsule will be getRootDirOfAllCapsules() + newBaseDir + filenameify(component.id))
533
+ * @returns a new capsule with the same content of the original capsule but with a new baseDir and all packages
534
+ * installed in the newBaseDir.
535
+ */
536
+ async cloneCapsule(originalCapsule, newBaseDir) {
537
+ const network = await this.isolateComponents([originalCapsule.component.id], {
538
+ baseDir: newBaseDir
539
+ });
540
+ const clonedCapsule = network.seedersCapsules[0];
541
+ await _fsExtra().default.copy(originalCapsule.path, clonedCapsule.path);
542
+ return clonedCapsule;
543
+ }
544
+
545
+ /**
546
+ * Create capsules for the provided components
547
+ * do not use this outside directly, use isolate components which build the entire network
548
+ * @param components
549
+ * @param opts
550
+ * @param legacyScope
551
+ */
552
+ /* eslint-disable complexity */
553
+ async createCapsules(components, capsulesDir, opts, legacyScope) {
554
+ this.logger.debug(`createCapsules, ${components.length} components`);
555
+ let longProcessLogger;
556
+ if (opts.context?.aspects) {
557
+ // const wsPath = opts.host?.path || 'unknown';
558
+ const wsPath = opts.context.workspaceName || opts.host?.path || opts.name || 'unknown';
559
+ longProcessLogger = this.logger.createLongProcessLogger(`ensuring ${_chalk().default.cyan(components.length.toString())} capsule(s) for all envs and aspects for ${_chalk().default.bold(wsPath)} at ${_chalk().default.bold(capsulesDir)}`);
560
+ }
561
+ const useNesting = this.dependencyResolver.isolatedCapsules() && opts.installOptions?.useNesting;
562
+ const installOptions = _objectSpread(_objectSpread(_objectSpread({}, DEFAULT_ISOLATE_INSTALL_OPTIONS), opts.installOptions), {}, {
563
+ useNesting
564
+ });
565
+ if (!opts.emptyRootDir) {
566
+ installOptions.dedupe = installOptions.dedupe && this.dependencyResolver.supportsDedupingOnExistingRoot();
567
+ }
568
+ const config = _objectSpread({
569
+ installPackages: true
570
+ }, opts);
571
+ if (opts.emptyRootDir) {
572
+ await _fsExtra().default.emptyDir(capsulesDir);
573
+ }
574
+ let capsules = await this.createCapsulesFromComponents(components, capsulesDir, config);
575
+ this.writeRootPackageJson(capsulesDir, this.getCapsuleDirHash(opts.baseDir || ''));
576
+ const allCapsuleList = _capsuleList().default.fromArray(capsules);
577
+ let capsuleList = allCapsuleList;
578
+ if (opts.getExistingAsIs) {
579
+ longProcessLogger?.end();
580
+ return capsuleList;
581
+ }
582
+ if (opts.skipIfExists) {
583
+ if (!installOptions.useNesting) {
584
+ const existingCapsules = _capsuleList().default.fromArray(capsuleList.filter(capsule => capsule.fs.existsSync('package.json')));
585
+ if (existingCapsules.length === capsuleList.length) {
586
+ longProcessLogger?.end();
587
+ return existingCapsules;
588
+ }
589
+ } else {
590
+ capsules = capsules.filter(capsule => !capsule.fs.existsSync('package.json'));
591
+ capsuleList = _capsuleList().default.fromArray(capsules);
592
+ }
593
+ }
594
+ const capsulesWithPackagesData = await this.getCapsulesPreviousPackageJson(capsules);
595
+ await this.writeComponentsInCapsules(components, capsuleList, legacyScope, opts);
596
+ await this.updateWithCurrentPackageJsonData(capsulesWithPackagesData, capsuleList);
597
+ if (installOptions.installPackages) {
598
+ const cachePackagesOnCapsulesRoot = opts.cachePackagesOnCapsulesRoot ?? false;
599
+ const linkingOptions = opts.linkingOptions ?? {};
600
+ let installLongProcessLogger;
601
+ // Only show the log message in case we are going to install something
602
+ if (capsuleList && capsuleList.length && !opts.context?.aspects) {
603
+ installLongProcessLogger = this.logger.createLongProcessLogger(`install packages in ${capsuleList.length} capsules`);
604
+ }
605
+ const rootLinks = await this.linkInCapsulesRoot(capsulesDir, capsuleList, linkingOptions);
606
+ if (installOptions.useNesting) {
607
+ await Promise.all(capsuleList.map(async (capsule, index) => {
608
+ const newCapsuleList = _capsuleList().default.fromArray([capsule]);
609
+ if (opts.cacheCapsulesDir && capsulesDir !== opts.cacheCapsulesDir && opts.cacheLockFileOnly) {
610
+ const cacheCapsuleDir = _path().default.join(opts.cacheCapsulesDir, (0, _path().basename)(capsule.path));
611
+ const lockFilePath = _path().default.join(cacheCapsuleDir, 'pnpm-lock.yaml');
612
+ const lockExists = await _fsExtra().default.pathExists(lockFilePath);
613
+ if (lockExists) {
614
+ try {
615
+ // this.logger.console(`moving lock file from ${lockFilePath} to ${capsule.path}`);
616
+ await (0, _fsExtra().copyFile)(lockFilePath, _path().default.join(capsule.path, 'pnpm-lock.yaml'));
617
+ } catch (err) {
618
+ // We can ignore the error, we don't want to break the flow. the file will be anyway re-generated
619
+ // in the target capsule. it will only be a bit slower.
620
+ this.logger.error(`failed moving lock file from cache folder path: ${lockFilePath} to local capsule at ${capsule.path} (even though the lock file seems to exist)`, err);
621
+ }
622
+ }
623
+ }
624
+ const linkedDependencies = await this.linkInCapsules(newCapsuleList, capsulesWithPackagesData);
625
+ if (index === 0) {
626
+ linkedDependencies[capsulesDir] = rootLinks;
627
+ }
628
+ await this.installInCapsules(capsule.path, newCapsuleList, installOptions, {
629
+ cachePackagesOnCapsulesRoot,
630
+ linkedDependencies,
631
+ packageManager: opts.packageManager,
632
+ nodeLinker: opts.nodeLinker
633
+ });
634
+ }));
635
+ } else {
636
+ const dependenciesGraph = opts.useDependenciesGraph ? await legacyScope?.getDependenciesGraphByComponentIds(capsuleList.getAllComponentIDs()) : undefined;
637
+ const linkedDependencies = await this.linkInCapsules(capsuleList, capsulesWithPackagesData);
638
+ linkedDependencies[capsulesDir] = rootLinks;
639
+ await this.installInCapsules(capsulesDir, capsuleList, installOptions, {
640
+ cachePackagesOnCapsulesRoot,
641
+ linkedDependencies,
642
+ packageManager: opts.packageManager,
643
+ dependenciesGraph
644
+ });
645
+ if (opts.useDependenciesGraph && dependenciesGraph == null) {
646
+ // If the graph was not present in the model, we use the just created lockfile inside the capsules
647
+ // to populate the graph.
648
+ await this.addDependenciesGraphToComponents(capsuleList, components, capsulesDir);
649
+ }
650
+ }
651
+ if (installLongProcessLogger) {
652
+ installLongProcessLogger.end('success');
653
+ }
654
+ }
655
+
656
+ // rewrite the package-json with the component dependencies in it. the original package.json
657
+ // that was written before, didn't have these dependencies in order for the package-manager to
658
+ // be able to install them without crushing when the versions don't exist yet
659
+ capsulesWithPackagesData.forEach(capsuleWithPackageData => {
660
+ const {
661
+ currentPackageJson,
662
+ capsule
663
+ } = capsuleWithPackageData;
664
+ if (!currentPackageJson) throw new Error(`isolator.createCapsules, unable to find currentPackageJson for ${capsule.component.id.toString()}`);
665
+ capsuleWithPackageData.capsule.fs.writeFileSync(_legacy().PACKAGE_JSON, JSON.stringify(currentPackageJson, null, 2));
666
+ });
667
+ await this.markCapsulesAsReady(capsuleList);
668
+ if (longProcessLogger) {
669
+ longProcessLogger.end();
670
+ }
671
+ // Only show this message if at least one new capsule created
672
+ if (longProcessLogger && capsuleList.length) {
673
+ // this.logger.consoleSuccess();
674
+ const capsuleListOutput = allCapsuleList.map(capsule => capsule.component.id.toString()).join(', ');
675
+ this.logger.consoleSuccess(`resolved aspect(s): ${_chalk().default.cyan(capsuleListOutput)}`);
676
+ }
677
+ return allCapsuleList;
678
+ }
679
+ /* eslint-enable complexity */
680
+
681
+ async addDependenciesGraphToComponents(capsuleList, components, capsulesDir) {
682
+ const componentIdByPkgName = this.dependencyResolver.createComponentIdByPkgNameMap(components);
683
+ const opts = {
684
+ componentIdByPkgName,
685
+ rootDir: capsulesDir
686
+ };
687
+ await Promise.all(capsuleList.map(capsule => this.dependencyResolver.addDependenciesGraph(capsule.component, _path().default.relative(capsulesDir, capsule.path), opts)));
688
+ }
689
+ async markCapsulesAsReady(capsuleList) {
690
+ await Promise.all(capsuleList.map(async capsule => {
691
+ return this.markCapsuleAsReady(capsule);
692
+ }));
693
+ }
694
+ async markCapsuleAsReady(capsule) {
695
+ const readyFilePath = this.getCapsuleReadyFilePath(capsule.path);
696
+ return _fsExtra().default.writeFile(readyFilePath, '');
697
+ }
698
+ removeCapsuleReadyFileSync(capsulePath) {
699
+ const readyFilePath = this.getCapsuleReadyFilePath(capsulePath);
700
+ const exist = _fsExtra().default.pathExistsSync(readyFilePath);
701
+ if (!exist) return;
702
+ _fsExtra().default.removeSync(readyFilePath);
703
+ }
704
+ writeCapsuleReadyFileSync(capsulePath) {
705
+ const readyFilePath = this.getCapsuleReadyFilePath(capsulePath);
706
+ const exist = _fsExtra().default.pathExistsSync(readyFilePath);
707
+ if (exist) return;
708
+ _fsExtra().default.writeFileSync(readyFilePath, '');
709
+ }
710
+ getCapsuleReadyFilePath(capsulePath) {
711
+ return _path().default.join(capsulePath, CAPSULE_READY_FILE);
712
+ }
713
+ async installInCapsules(capsulesDir, capsuleList, isolateInstallOptions, opts) {
714
+ const installer = this.dependencyResolver.getInstaller({
715
+ rootDir: capsulesDir,
716
+ cacheRootDirectory: opts.cachePackagesOnCapsulesRoot ? capsulesDir : undefined,
717
+ installingContext: {
718
+ inCapsule: true
719
+ },
720
+ packageManager: opts.packageManager,
721
+ nodeLinker: opts.nodeLinker
722
+ });
723
+ // When using isolator we don't want to use the policy defined in the workspace directly,
724
+ // we only want to instal deps from components and the peer from the workspace
725
+
726
+ const peerOnlyPolicy = this.getWorkspacePeersOnlyPolicy();
727
+ const installOptions = {
728
+ installTeambitBit: !!isolateInstallOptions.installTeambitBit,
729
+ packageManagerConfigRootDir: isolateInstallOptions.packageManagerConfigRootDir,
730
+ resolveVersionsFromDependenciesOnly: true,
731
+ linkedDependencies: opts.linkedDependencies,
732
+ forcedHarmonyVersion: this.dependencyResolver.harmonyVersionInRootPolicy(),
733
+ excludeExtensionsDependencies: true,
734
+ dedupeInjectedDeps: true,
735
+ dependenciesGraph: opts.dependenciesGraph
736
+ };
737
+ const packageManagerInstallOptions = {
738
+ autoInstallPeers: this.dependencyResolver.config.autoInstallPeers,
739
+ dedupe: isolateInstallOptions.dedupe,
740
+ copyPeerToRuntimeOnComponents: isolateInstallOptions.copyPeerToRuntimeOnComponents,
741
+ copyPeerToRuntimeOnRoot: isolateInstallOptions.copyPeerToRuntimeOnRoot,
742
+ installPeersFromEnvs: isolateInstallOptions.installPeersFromEnvs,
743
+ nmSelfReferences: this.dependencyResolver.config.capsuleSelfReference,
744
+ overrides: this.dependencyResolver.config.capsulesOverrides || this.dependencyResolver.config.overrides,
745
+ hoistPatterns: this.dependencyResolver.config.hoistPatterns,
746
+ rootComponentsForCapsules: this.dependencyResolver.isolatedCapsules(),
747
+ useNesting: isolateInstallOptions.useNesting,
748
+ keepExistingModulesDir: this.dependencyResolver.isolatedCapsules(),
749
+ hasRootComponents: this.dependencyResolver.isolatedCapsules(),
750
+ hoistWorkspacePackages: true
751
+ };
752
+ await installer.install(capsulesDir, peerOnlyPolicy, this.toComponentMap(capsuleList), installOptions, packageManagerInstallOptions);
753
+ }
754
+ async linkInCapsules(capsuleList, capsulesWithPackagesData) {
755
+ let nestedLinks;
756
+ if (!this.dependencyResolver.isolatedCapsules()) {
757
+ const capsulesWithModifiedPackageJson = this.getCapsulesWithModifiedPackageJson(capsulesWithPackagesData);
758
+ nestedLinks = await (0, _symlinkDependenciesToCapsules().symlinkDependenciesToCapsules)(capsulesWithModifiedPackageJson, capsuleList, this.logger);
759
+ }
760
+ return nestedLinks ?? {};
761
+ }
762
+ async linkInCapsulesRoot(capsulesDir, capsuleList, linkingOptions) {
763
+ const linker = this.dependencyResolver.getLinker({
764
+ rootDir: capsulesDir,
765
+ linkingOptions,
766
+ linkingContext: {
767
+ inCapsule: true
768
+ }
769
+ });
770
+ const {
771
+ linkedRootDeps
772
+ } = await linker.calculateLinkedDeps(capsulesDir, this.toComponentMap(capsuleList), _objectSpread(_objectSpread({}, linkingOptions), {}, {
773
+ linkNestedDepsInNM: !this.dependencyResolver.isolatedCapsules() && linkingOptions.linkNestedDepsInNM
774
+ }));
775
+ let rootLinks;
776
+ if (!this.dependencyResolver.isolatedCapsules()) {
777
+ rootLinks = await (0, _symlinkDependenciesToCapsules().symlinkOnCapsuleRoot)(capsuleList, this.logger, capsulesDir);
778
+ } else {
779
+ const coreAspectIds = this.aspectLoader.getCoreAspectIds();
780
+ const coreAspectCapsules = _capsuleList().default.fromArray(capsuleList.filter(capsule => {
781
+ const [compIdWithoutVersion] = capsule.component.id.toString().split('@');
782
+ return coreAspectIds.includes(compIdWithoutVersion);
783
+ }));
784
+ rootLinks = await (0, _symlinkDependenciesToCapsules().symlinkOnCapsuleRoot)(coreAspectCapsules, this.logger, capsulesDir);
785
+ }
786
+ return _objectSpread(_objectSpread({}, linkedRootDeps), this.toLocalLinks(rootLinks));
787
+ }
788
+ toLocalLinks(rootLinks) {
789
+ const localLinks = [];
790
+ if (rootLinks) {
791
+ rootLinks.forEach(link => {
792
+ localLinks.push(this.linkDetailToLocalDepEntry(link));
793
+ });
794
+ }
795
+ return Object.fromEntries(localLinks.map(([key, value]) => [key, `link:${value}`]));
796
+ }
797
+ linkDetailToLocalDepEntry(linkDetail) {
798
+ return [linkDetail.packageName, linkDetail.from];
799
+ }
800
+ getCapsulesWithModifiedPackageJson(capsulesWithPackagesData) {
801
+ const capsulesWithModifiedPackageJson = capsulesWithPackagesData.filter(capsuleWithPackageData => {
802
+ const packageJsonHasChanged = this.wereDependenciesInPackageJsonChanged(capsuleWithPackageData);
803
+ // @todo: when a component is tagged, it changes all package-json of its dependents, but it
804
+ // should not trigger any "npm install" because they dependencies are symlinked by us
805
+ return packageJsonHasChanged;
806
+ }).map(capsuleWithPackageData => capsuleWithPackageData.capsule);
807
+ return capsulesWithModifiedPackageJson;
808
+ }
809
+ async writeComponentsInCapsules(components, capsuleList, legacyScope, opts) {
810
+ const modifiedComps = [];
811
+ const unmodifiedComps = [];
812
+ await Promise.all(components.map(async component => {
813
+ if (await _capsuleList().default.capsuleUsePreviouslySavedDists(component)) {
814
+ unmodifiedComps.push(component);
815
+ } else {
816
+ modifiedComps.push(component);
817
+ }
818
+ }));
819
+ const legacyUnmodifiedComps = unmodifiedComps.map(component => component.state._consumer.clone());
820
+ const legacyModifiedComps = modifiedComps.map(component => component.state._consumer.clone());
821
+ const legacyComponents = [...legacyUnmodifiedComps, ...legacyModifiedComps];
822
+ if (legacyScope && unmodifiedComps.length) await (0, _component2().importMultipleDistsArtifacts)(legacyScope, legacyUnmodifiedComps);
823
+ const allIds = _componentId().ComponentIdList.fromArray(legacyComponents.map(c => c.id));
824
+ const getParentsComp = () => {
825
+ const artifactsFrom = opts?.populateArtifactsFrom;
826
+ if (!artifactsFrom) return undefined;
827
+ if (!legacyScope) throw new Error('populateArtifactsFrom is set but legacyScope is not defined');
828
+ return Promise.all(artifactsFrom.map(id => legacyScope.getConsumerComponent(id)));
829
+ };
830
+ const populateArtifactsFromComps = await getParentsComp();
831
+ await Promise.all(components.map(async component => {
832
+ const capsule = capsuleList.getCapsule(component.id);
833
+ if (!capsule) return;
834
+ const scope = (await _capsuleList().default.capsuleUsePreviouslySavedDists(component)) || opts?.populateArtifactsFrom ? legacyScope : undefined;
835
+ const dataToPersist = await this.populateComponentsFilesToWriteForCapsule(component, allIds, scope, opts, populateArtifactsFromComps);
836
+ await dataToPersist.persistAllToCapsule(capsule, {
837
+ keepExistingCapsule: true
838
+ });
839
+ }));
840
+ }
841
+ getWorkspacePeersOnlyPolicy() {
842
+ const workspacePolicy = this.dependencyResolver.getWorkspacePolicy();
843
+ const peerOnlyPolicy = workspacePolicy.byLifecycleType('peer');
844
+ return peerOnlyPolicy;
845
+ }
846
+ toComponentMap(capsuleList) {
847
+ const tuples = capsuleList.map(capsule => {
848
+ return [capsule.component, capsule.path];
849
+ });
850
+ return _component().ComponentMap.create(tuples);
851
+ }
852
+ async list(rootDir) {
853
+ try {
854
+ const capsules = await _fsExtra().default.readdir(rootDir);
855
+ const withoutNodeModules = capsules.filter(c => c !== 'node_modules');
856
+ const capsuleFullPaths = withoutNodeModules.map(c => _path().default.join(rootDir, c));
857
+ return {
858
+ capsules: capsuleFullPaths
859
+ };
860
+ } catch (e) {
861
+ if (e.code === 'ENOENT') {
862
+ return {
863
+ capsules: []
864
+ };
865
+ }
866
+ throw e;
867
+ }
868
+ }
869
+ registerCapsuleTransferFn(fn) {
870
+ this.capsuleTransferSlot.register(fn);
871
+ }
872
+ getCapsuleTransferFn() {
873
+ return this.capsuleTransferSlot.values()[0] || this.getDefaultCapsuleTransferFn();
874
+ }
875
+ getDefaultCapsuleTransferFn() {
876
+ return async (source, target) => {
877
+ return _fsExtra().default.move(source, target, {
878
+ overwrite: true
879
+ });
880
+ };
881
+ }
882
+ getCapsuleDirHash(baseDir) {
883
+ return (0, _objectHash().default)(baseDir).substring(0, CAPSULE_DIR_LENGTH);
884
+ }
885
+
886
+ /** @deprecated use the new function signature with an object parameter instead */
887
+
888
+ getCapsulesRootDir(getCapsuleDirOpts, rootBaseDir, useHash = true, useDatedDirs = false, datedDirId) {
889
+ if (typeof getCapsuleDirOpts === 'string') {
890
+ getCapsuleDirOpts = {
891
+ baseDir: getCapsuleDirOpts,
892
+ rootBaseDir,
893
+ useHash,
894
+ useDatedDirs,
895
+ datedDirId
896
+ };
897
+ }
898
+ const getCapsuleDirOptsWithDefaults = _objectSpread({
899
+ useHash: true,
900
+ useDatedDirs: false,
901
+ cacheLockFileOnly: false
902
+ }, getCapsuleDirOpts);
903
+ const capsulesRootBaseDir = getCapsuleDirOptsWithDefaults.rootBaseDir || this.getRootDirOfAllCapsules();
904
+ if (getCapsuleDirOptsWithDefaults.useDatedDirs) {
905
+ const date = new Date();
906
+ const month = date.getMonth() < 12 ? date.getMonth() + 1 : 1;
907
+ const dateDir = `${date.getFullYear()}-${month}-${date.getDate()}`;
908
+ const defaultDatedBaseDir = 'dated-capsules';
909
+ const datedBaseDir = this.configStore.getConfig(_legacy().CFG_CAPSULES_SCOPES_ASPECTS_DATED_DIR) || defaultDatedBaseDir;
910
+ let hashDir;
911
+ const finalDatedDirId = getCapsuleDirOpts.datedDirId;
912
+ if (finalDatedDirId && this._datedHashForName.has(finalDatedDirId)) {
913
+ // Make sure in the same process we always use the same hash for the same datedDirId
914
+ hashDir = this._datedHashForName.get(finalDatedDirId);
915
+ } else {
916
+ hashDir = (0, _uuid().v4)();
917
+ if (finalDatedDirId) {
918
+ this._datedHashForName.set(finalDatedDirId, hashDir);
919
+ }
920
+ }
921
+ return _path().default.join(capsulesRootBaseDir, datedBaseDir, dateDir, hashDir);
922
+ }
923
+ const dir = getCapsuleDirOptsWithDefaults.useHash ? this.getCapsuleDirHash(getCapsuleDirOptsWithDefaults.baseDir) : getCapsuleDirOptsWithDefaults.baseDir;
924
+ return _path().default.join(capsulesRootBaseDir, dir);
925
+ }
926
+ async deleteCapsules(rootDir) {
927
+ const dirToDelete = rootDir || this.getRootDirOfAllCapsules();
928
+ await _fsExtra().default.remove(dirToDelete);
929
+ return dirToDelete;
930
+ }
931
+ writeRootPackageJson(capsulesDir, hashDir) {
932
+ const rootPackageJson = _path().default.join(capsulesDir, 'package.json');
933
+ if (!_fsExtra().default.existsSync(rootPackageJson)) {
934
+ const packageJson = {
935
+ name: `capsules-${hashDir}`,
936
+ 'bit-capsule': true
937
+ };
938
+ _fsExtra().default.outputJsonSync(rootPackageJson, packageJson);
939
+ }
940
+ }
941
+ async createCapsulesFromComponents(components, baseDir, opts) {
942
+ this.logger.debug(`createCapsulesFromComponents: ${components.length} components`);
943
+ const capsules = await (0, _pMap().default)(components, component => {
944
+ return _capsule().Capsule.createFromComponent(component, baseDir, opts);
945
+ }, {
946
+ concurrency: (0, _harmonyModules2().concurrentComponentsLimit)()
947
+ });
948
+ return capsules;
949
+ }
950
+ getRootDirOfAllCapsules() {
951
+ return this.globalConfig.getGlobalCapsulesBaseDir();
952
+ }
953
+ wereDependenciesInPackageJsonChanged(capsuleWithPackageData) {
954
+ const {
955
+ previousPackageJson,
956
+ currentPackageJson
957
+ } = capsuleWithPackageData;
958
+ if (!previousPackageJson) return true;
959
+ // @ts-ignore at this point, currentPackageJson is set
960
+ return _legacy().DEPENDENCIES_FIELDS.some(field => !(0, _lodash().isEqual)(previousPackageJson[field], currentPackageJson[field]));
961
+ }
962
+ async getCapsulesPreviousPackageJson(capsules) {
963
+ return Promise.all(capsules.map(async capsule => {
964
+ const packageJsonPath = _path().default.join(capsule.path, 'package.json');
965
+ let previousPackageJson = null;
966
+ try {
967
+ const previousPackageJsonRaw = await capsule.fs.promises.readFile(packageJsonPath, {
968
+ encoding: 'utf8'
969
+ });
970
+ previousPackageJson = JSON.parse(previousPackageJsonRaw);
971
+ } catch {
972
+ // package-json doesn't exist in the capsule, that's fine, it'll be considered as a cache miss
973
+ }
974
+ return {
975
+ capsule,
976
+ previousPackageJson
977
+ };
978
+ }));
979
+ }
980
+ async updateWithCurrentPackageJsonData(capsulesWithPackagesData, capsules) {
981
+ return Promise.all(capsules.map(async capsule => {
982
+ const packageJson = await this.getCurrentPackageJson(capsule, capsules);
983
+ const found = capsulesWithPackagesData.filter(c => c.capsule.component.id.isEqual(capsule.component.id));
984
+ if (!found.length) throw new Error(`updateWithCurrentPackageJsonData unable to find ${capsule.component.id}`);
985
+ if (found.length > 1) throw new Error(`updateWithCurrentPackageJsonData found duplicate capsules: ${capsule.component.id.toString()}""`);
986
+ found[0].currentPackageJson = packageJson.packageJsonObject;
987
+ }));
988
+ }
989
+ async getCurrentPackageJson(capsule, capsules) {
990
+ const component = capsule.component;
991
+ const currentVersion = (0, _componentPackageVersion().getComponentPackageVersion)(component);
992
+ const getComponentDepsManifest = async dependencies => {
993
+ const manifest = {
994
+ dependencies: {},
995
+ devDependencies: {},
996
+ peerDependencies: {}
997
+ };
998
+ const compDeps = dependencies.toTypeArray('component');
999
+ const promises = compDeps.map(async dep => {
1000
+ const depCapsule = capsules.getCapsule(dep.componentId);
1001
+ let version = dep.version;
1002
+ if (depCapsule) {
1003
+ version = (0, _componentPackageVersion().getComponentPackageVersion)(depCapsule.component);
1004
+ } else {
1005
+ version = (0, _componentPackageVersion().snapToSemver)(version);
1006
+ }
1007
+ const keyName = _dependencyResolver().KEY_NAME_BY_LIFECYCLE_TYPE[dep.lifecycle];
1008
+ const entry = dep.toManifest();
1009
+ if (entry) {
1010
+ manifest[keyName][entry.packageName] = dep.versionRange && dep.versionRange !== '+' ? dep.versionRange : version;
1011
+ }
1012
+ });
1013
+ await Promise.all(promises);
1014
+ return manifest;
1015
+ };
1016
+ const deps = this.dependencyResolver.getDependencies(component);
1017
+ const manifest = await getComponentDepsManifest(deps);
1018
+
1019
+ // component.packageJsonFile is not available here. we don't mutate the component object for capsules.
1020
+ // also, don't use `PackageJsonFile.createFromComponent`, as it looses the intermediate changes
1021
+ // such as postInstall scripts for custom-module-resolution.
1022
+ const packageJson = _component2().PackageJsonFile.loadFromCapsuleSync(capsule.path);
1023
+ const addDependencies = packageJsonFile => {
1024
+ packageJsonFile.addDependencies(manifest.dependencies);
1025
+ packageJsonFile.addDevDependencies(manifest.devDependencies);
1026
+ packageJsonFile.addPeerDependencies(manifest.peerDependencies);
1027
+ };
1028
+ addDependencies(packageJson);
1029
+ packageJson.addOrUpdateProperty('version', currentVersion);
1030
+ return packageJson;
1031
+ }
1032
+ async populateComponentsFilesToWriteForCapsule(component, ids, legacyScope, opts, populateArtifactsFromComps) {
1033
+ const legacyComp = component.state._consumer;
1034
+ const dataToPersist = new (_component2().DataToPersist)();
1035
+ const clonedFiles = legacyComp.files.map(file => file.clone());
1036
+ const writeToPath = '.';
1037
+ clonedFiles.forEach(file => file.updatePaths({
1038
+ newBase: writeToPath
1039
+ }));
1040
+ dataToPersist.removePath(new (_component2().RemovePath)(writeToPath));
1041
+ clonedFiles.map(file => dataToPersist.addFile(file));
1042
+ const packageJson = this.preparePackageJsonToWrite(component, writeToPath, ids);
1043
+ if (!legacyComp.id.hasVersion()) {
1044
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1045
+ packageJson.addOrUpdateProperty('version', _semver().default.inc(legacyComp.version, 'prerelease') || '0.0.1-0');
1046
+ }
1047
+ await _workspaceModules().PackageJsonTransformer.applyTransformers(component, packageJson);
1048
+ const valuesToMerge = legacyComp.overrides.componentOverridesPackageJsonData;
1049
+ packageJson.mergePackageJsonObject(valuesToMerge);
1050
+ if (populateArtifactsFromComps && !opts?.populateArtifactsIgnorePkgJson) {
1051
+ const compParent = this.getCompForArtifacts(component, populateArtifactsFromComps);
1052
+ this.mergePkgJsonFromLastBuild(compParent, packageJson);
1053
+ }
1054
+ dataToPersist.addFile(packageJson.toVinylFile());
1055
+ const artifacts = await this.getArtifacts(component, legacyScope, populateArtifactsFromComps);
1056
+ dataToPersist.addManyFiles(artifacts);
1057
+ return dataToPersist;
1058
+ }
1059
+ mergePkgJsonFromLastBuild(component, packageJson) {
1060
+ const suffix = `for ${component.id.toString()}. to workaround this, use --ignore-last-pkg-json flag`;
1061
+ const aspectsData = component.extensions.findExtension('teambit.pipelines/builder')?.data?.aspectsData;
1062
+ if (!aspectsData) throw new Error(`getPkgJsonFromLastBuild, unable to find builder aspects data ${suffix}`);
1063
+ const data = aspectsData?.find(aspectData => aspectData.aspectId === 'teambit.pkg/pkg');
1064
+ if (!data) throw new Error(`getPkgJsonFromLastBuild, unable to find pkg aspect data ${suffix}`);
1065
+ const pkgJsonLastBuild = data?.data?.pkgJson;
1066
+ if (!pkgJsonLastBuild) throw new Error(`getPkgJsonFromLastBuild, unable to find pkgJson of pkg aspect ${suffix}`);
1067
+ const current = packageJson.packageJsonObject;
1068
+ pkgJsonLastBuild.componentId = current.componentId;
1069
+ pkgJsonLastBuild.version = current.version;
1070
+ const mergeDeps = (currentDeps, depsFromLastBuild) => {
1071
+ if (!depsFromLastBuild) return;
1072
+ if (!currentDeps) return depsFromLastBuild;
1073
+ Object.keys(depsFromLastBuild).forEach(depName => {
1074
+ if (!currentDeps[depName]) return;
1075
+ depsFromLastBuild[depName] = currentDeps[depName];
1076
+ });
1077
+ return depsFromLastBuild;
1078
+ };
1079
+ pkgJsonLastBuild.dependencies = mergeDeps(current.dependencies, pkgJsonLastBuild.dependencies);
1080
+ pkgJsonLastBuild.devDependencies = mergeDeps(current.devDependencies, pkgJsonLastBuild.devDependencies);
1081
+ pkgJsonLastBuild.peerDependencies = mergeDeps(current.peerDependencies, pkgJsonLastBuild.peerDependencies);
1082
+ packageJson.mergePackageJsonObject(pkgJsonLastBuild);
1083
+ }
1084
+ getCompForArtifacts(component, populateArtifactsFromComps) {
1085
+ const compParent = populateArtifactsFromComps.find(comp => comp.id.isEqual(component.id, {
1086
+ ignoreVersion: true
1087
+ }));
1088
+ if (!compParent) {
1089
+ throw new Error(`isolator, unable to find where to populate the artifacts from for ${component.id.toString()}`);
1090
+ }
1091
+ return compParent;
1092
+ }
1093
+ preparePackageJsonToWrite(component, bitDir, componentDepsToIgnore) {
1094
+ const legacyComp = component.state._consumer;
1095
+ const compDeps = this.dependencyResolver.getComponentDependencies(component);
1096
+ this.logger.debug(`package-json.preparePackageJsonToWrite. bitDir ${bitDir}.`);
1097
+ const getBitDependencies = dependencies => {
1098
+ return dependencies.reduce((acc, depId) => {
1099
+ if (componentDepsToIgnore.searchWithoutVersion(depId)) {
1100
+ return acc;
1101
+ }
1102
+ const fromDepsResolver = compDeps.find(dep => dep.componentId.isEqualWithoutVersion(depId));
1103
+ const versionWithRange = fromDepsResolver?.versionRange;
1104
+ const packageDependency = depId.version;
1105
+ const packageName = (0, _pkgModules().componentIdToPackageName)(_objectSpread(_objectSpread({}, legacyComp), {}, {
1106
+ id: depId,
1107
+ isDependency: true
1108
+ }));
1109
+ acc[packageName] = versionWithRange || packageDependency;
1110
+ return acc;
1111
+ }, {});
1112
+ };
1113
+ const bitDependencies = getBitDependencies(legacyComp.dependencies.getAllIds());
1114
+ const bitDevDependencies = getBitDependencies(legacyComp.devDependencies.getAllIds());
1115
+ const bitExtensionDependencies = getBitDependencies(legacyComp.extensions.extensionsBitIds);
1116
+ const packageJson = _component2().PackageJsonFile.createFromComponent(bitDir, legacyComp);
1117
+ const main = (0, _legacy2().pathNormalizeToLinux)(legacyComp.mainFile);
1118
+ packageJson.addOrUpdateProperty('main', main);
1119
+ const addDependencies = packageJsonFile => {
1120
+ packageJsonFile.addDependencies(bitDependencies);
1121
+ packageJsonFile.addDevDependencies(_objectSpread(_objectSpread({}, bitDevDependencies), bitExtensionDependencies));
1122
+ };
1123
+ addDependencies(packageJson);
1124
+ const currentVersion = (0, _componentPackageVersion().getComponentPackageVersion)(component);
1125
+ packageJson.addOrUpdateProperty('version', currentVersion);
1126
+ return packageJson;
1127
+ }
1128
+
1129
+ /**
1130
+ * currently, it writes all artifacts.
1131
+ * later, this responsibility might move to pkg extension, which could write only artifacts
1132
+ * that are set in package.json.files[], to have a similar structure of a package.
1133
+ */
1134
+ async getArtifacts(component, legacyScope, populateArtifactsFromComps) {
1135
+ const legacyComp = component.state._consumer;
1136
+ if (!legacyScope) {
1137
+ // when capsules are written via the workspace, do not write artifacts, they get created by
1138
+ // build-pipeline. when capsules are written via the scope, we do need the dists.
1139
+ return [];
1140
+ }
1141
+ if (legacyComp.buildStatus !== 'succeed' && !populateArtifactsFromComps) {
1142
+ // this is important for "bit sign" when on lane to not go to the original scope
1143
+ return [];
1144
+ }
1145
+ const artifactFilesToFetch = async () => {
1146
+ if (populateArtifactsFromComps) {
1147
+ const compParent = this.getCompForArtifacts(component, populateArtifactsFromComps);
1148
+ return (0, _component2().getArtifactFilesExcludeExtension)(compParent.extensions, 'teambit.pkg/pkg');
1149
+ }
1150
+ const extensionsNamesForArtifacts = ['teambit.compilation/compiler'];
1151
+ return (0, _lodash().flatten)(extensionsNamesForArtifacts.map(extName => (0, _component2().getArtifactFilesByExtension)(legacyComp.extensions, extName)));
1152
+ };
1153
+ const artifactsFiles = await artifactFilesToFetch();
1154
+ const artifactsVinylFlattened = [];
1155
+ await Promise.all(artifactsFiles.map(async artifactFiles => {
1156
+ if (!artifactFiles) return;
1157
+ if (!(artifactFiles instanceof _component2().ArtifactFiles)) {
1158
+ artifactFiles = (0, _component2().deserializeArtifactFiles)(artifactFiles);
1159
+ }
1160
+ // fyi, if this is coming from the isolator aspect, it is optimized to import all at once.
1161
+ // see artifact-files.importMultipleDistsArtifacts().
1162
+ const vinylFiles = await artifactFiles.getVinylsAndImportIfMissing(legacyComp.id, legacyScope);
1163
+ artifactsVinylFlattened.push(...vinylFiles);
1164
+ }));
1165
+ const artifactsDir = legacyComp.writtenPath;
1166
+ if (artifactsDir) {
1167
+ artifactsVinylFlattened.forEach(a => a.updatePaths({
1168
+ newBase: artifactsDir
1169
+ }));
1170
+ }
1171
+ return artifactsVinylFlattened;
1172
+ }
1173
+
1174
+ /**
1175
+ * Filter out unmodified exported dependencies to optimize capsule creation.
1176
+ * These dependencies can be installed as packages instead of creating capsules.
1177
+ */
1178
+ async filterUnmodifiedExportedDependencies(components, seederIds, host) {
1179
+ this.logger.debug(`filterUnmodifiedExportedDependencies: filtering ${components.length} components`);
1180
+ const scope = this.componentAspect.getHost('teambit.scope/scope');
1181
+ // @ts-ignore it's there, but we can't have the type of ScopeMain here to not create a circular dependency
1182
+ const remotes = await scope.getRemoteScopes();
1183
+ const filtered = [];
1184
+ for (const component of components) {
1185
+ const componentIdStr = component.id.toString();
1186
+ const isSeeder = seederIds.some(seederId => component.id.isEqual(seederId, {
1187
+ ignoreVersion: true
1188
+ }));
1189
+ if (isSeeder) {
1190
+ // Always include seeders (modified components and their dependents)
1191
+ filtered.push(component);
1192
+ continue;
1193
+ }
1194
+ // For dependencies, check if they are exported and unmodified
1195
+
1196
+ // Check if component is modified
1197
+ // Normally, when running "bit build" with no args, only the seeders are modified, so this check is not needed.
1198
+ // However, when running "bit build comp1", comp1 might have modified dependencies. we want to include them.
1199
+ // In terms of performance, I checked on a big workspace, it costs zero time, because the modification data is cached.
1200
+ const isModified = await component.isModified();
1201
+ if (isModified) {
1202
+ // Always include modified components
1203
+ filtered.push(component);
1204
+ continue;
1205
+ }
1206
+ const isPublished = component.get('teambit.pkg/pkg')?.config?.packageJson?.publishConfig;
1207
+ const canBeInstalled = host.isExported(component.id) && (remotes.isHub(component.id.scope) || isPublished);
1208
+ if (canBeInstalled) {
1209
+ this.logger.debug(`[OPTIMIZATION] Excluding unmodified exported dependency: ${componentIdStr}`);
1210
+ } else {
1211
+ filtered.push(component);
1212
+ }
1213
+ }
1214
+ this.logger.debug(`filterUnmodifiedExportedDependencies: kept ${filtered.length} out of ${components.length} components`);
1215
+ return filtered;
1216
+ }
1217
+ }
1218
+ exports.IsolatorMain = IsolatorMain;
1219
+ _defineProperty(IsolatorMain, "runtime", _cli().MainRuntime);
1220
+ _defineProperty(IsolatorMain, "dependencies", [_dependencyResolver().DependencyResolverAspect, _logger().LoggerAspect, _component().ComponentAspect, _graph().GraphAspect, _globalConfig().GlobalConfigAspect, _aspectLoader().AspectLoaderAspect, _cli().CLIAspect, _configStore().ConfigStoreAspect]);
1221
+ _defineProperty(IsolatorMain, "slots", [_harmony().Slot.withType()]);
1222
+ _defineProperty(IsolatorMain, "defaultConfig", {});
1223
+ _isolator().IsolatorAspect.addRuntime(IsolatorMain);
1224
+
1225
+ //# sourceMappingURL=isolator.main.runtime.js.map