@teambit/objects 0.0.0-00042bc99514ea12d897f81bcd0181e2b034c615

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 (121) hide show
  1. package/dist/fixtures/version-model-extended.json +48 -0
  2. package/dist/fixtures/version-model-object.json +87 -0
  3. package/dist/index.d.ts +19 -0
  4. package/dist/index.js +371 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/models/dependencies-graph.d.ts +46 -0
  7. package/dist/models/dependencies-graph.js +105 -0
  8. package/dist/models/dependencies-graph.js.map +1 -0
  9. package/dist/models/detach-heads.d.ts +25 -0
  10. package/dist/models/detach-heads.js +84 -0
  11. package/dist/models/detach-heads.js.map +1 -0
  12. package/dist/models/export-metadata.d.ts +24 -0
  13. package/dist/models/export-metadata.js +74 -0
  14. package/dist/models/export-metadata.js.map +1 -0
  15. package/dist/models/index.d.ts +10 -0
  16. package/dist/models/index.js +125 -0
  17. package/dist/models/index.js.map +1 -0
  18. package/dist/models/lane-history.d.ts +43 -0
  19. package/dist/models/lane-history.js +131 -0
  20. package/dist/models/lane-history.js.map +1 -0
  21. package/dist/models/lane-history.spec.d.ts +1 -0
  22. package/dist/models/lane-history.spec.js +46 -0
  23. package/dist/models/lane-history.spec.js.map +1 -0
  24. package/dist/models/lane.d.ts +128 -0
  25. package/dist/models/lane.js +485 -0
  26. package/dist/models/lane.js.map +1 -0
  27. package/dist/models/model-component.d.ts +338 -0
  28. package/dist/models/model-component.js +1509 -0
  29. package/dist/models/model-component.js.map +1 -0
  30. package/dist/models/model-component.spec.d.ts +1 -0
  31. package/dist/models/model-component.spec.js +71 -0
  32. package/dist/models/model-component.spec.js.map +1 -0
  33. package/dist/models/scopeMeta.d.ts +20 -0
  34. package/dist/models/scopeMeta.js +68 -0
  35. package/dist/models/scopeMeta.js.map +1 -0
  36. package/dist/models/source.d.ts +10 -0
  37. package/dist/models/source.js +42 -0
  38. package/dist/models/source.js.map +1 -0
  39. package/dist/models/symlink.d.ts +30 -0
  40. package/dist/models/symlink.js +91 -0
  41. package/dist/models/symlink.js.map +1 -0
  42. package/dist/models/version-history.d.ts +59 -0
  43. package/dist/models/version-history.js +296 -0
  44. package/dist/models/version-history.js.map +1 -0
  45. package/dist/models/version.d.ts +288 -0
  46. package/dist/models/version.js +780 -0
  47. package/dist/models/version.js.map +1 -0
  48. package/dist/models/version.spec.d.ts +1 -0
  49. package/dist/models/version.spec.js +332 -0
  50. package/dist/models/version.spec.js.map +1 -0
  51. package/dist/objects/bit-object-list.d.ts +24 -0
  52. package/dist/objects/bit-object-list.js +65 -0
  53. package/dist/objects/bit-object-list.js.map +1 -0
  54. package/dist/objects/index.d.ts +5 -0
  55. package/dist/objects/index.js +60 -0
  56. package/dist/objects/index.js.map +1 -0
  57. package/dist/objects/object-list-to-graph.d.ts +13 -0
  58. package/dist/objects/object-list-to-graph.js +93 -0
  59. package/dist/objects/object-list-to-graph.js.map +1 -0
  60. package/dist/objects/object-list.d.ts +58 -0
  61. package/dist/objects/object-list.js +389 -0
  62. package/dist/objects/object-list.js.map +1 -0
  63. package/dist/objects/object.d.ts +35 -0
  64. package/dist/objects/object.js +189 -0
  65. package/dist/objects/object.js.map +1 -0
  66. package/dist/objects/objects-readable-generator.d.ts +31 -0
  67. package/dist/objects/objects-readable-generator.js +203 -0
  68. package/dist/objects/objects-readable-generator.js.map +1 -0
  69. package/dist/objects/raw-object.d.ts +23 -0
  70. package/dist/objects/raw-object.js +145 -0
  71. package/dist/objects/raw-object.js.map +1 -0
  72. package/dist/objects/ref.d.ts +14 -0
  73. package/dist/objects/ref.js +45 -0
  74. package/dist/objects/ref.js.map +1 -0
  75. package/dist/objects/repository.d.ts +165 -0
  76. package/dist/objects/repository.js +866 -0
  77. package/dist/objects/repository.js.map +1 -0
  78. package/dist/objects/scope-index.d.ts +74 -0
  79. package/dist/objects/scope-index.js +255 -0
  80. package/dist/objects/scope-index.js.map +1 -0
  81. package/dist/objects/scope-index.spec.d.ts +1 -0
  82. package/dist/objects/scope-index.spec.js +152 -0
  83. package/dist/objects/scope-index.spec.js.map +1 -0
  84. package/dist/objects.aspect.d.ts +2 -0
  85. package/dist/objects.aspect.js +18 -0
  86. package/dist/objects.aspect.js.map +1 -0
  87. package/dist/objects.main.runtime.d.ts +7 -0
  88. package/dist/objects.main.runtime.js +36 -0
  89. package/dist/objects.main.runtime.js.map +1 -0
  90. package/dist/preview-1781548568469.js +7 -0
  91. package/fixtures/version-model-extended.json +48 -0
  92. package/fixtures/version-model-object.json +87 -0
  93. package/models/dependencies-graph.ts +120 -0
  94. package/models/detach-heads.ts +79 -0
  95. package/models/export-metadata.ts +56 -0
  96. package/models/index.ts +11 -0
  97. package/models/lane-history.spec.ts +35 -0
  98. package/models/lane-history.ts +131 -0
  99. package/models/lane.ts +400 -0
  100. package/models/model-component.spec.ts +55 -0
  101. package/models/model-component.ts +1522 -0
  102. package/models/scopeMeta.ts +58 -0
  103. package/models/source.ts +31 -0
  104. package/models/symlink.ts +66 -0
  105. package/models/version-history.ts +283 -0
  106. package/models/version.spec.ts +280 -0
  107. package/models/version.ts +821 -0
  108. package/objects/bit-object-list.ts +59 -0
  109. package/objects/index.ts +6 -0
  110. package/objects/object-list-to-graph.ts +69 -0
  111. package/objects/object-list.ts +327 -0
  112. package/objects/object.ts +152 -0
  113. package/objects/objects-readable-generator.ts +174 -0
  114. package/objects/raw-object.ts +132 -0
  115. package/objects/ref.ts +45 -0
  116. package/objects/repository.ts +780 -0
  117. package/objects/scope-index.spec.ts +95 -0
  118. package/objects/scope-index.ts +197 -0
  119. package/package.json +97 -0
  120. package/types/asset.d.ts +41 -0
  121. package/types/style.d.ts +42 -0
@@ -0,0 +1,1509 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.VERSION_ZERO = void 0;
7
+ function _lodash() {
8
+ const data = require("lodash");
9
+ _lodash = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _asyncMutex() {
15
+ const data = require("async-mutex");
16
+ _asyncMutex = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function semver() {
22
+ const data = _interopRequireWildcard(require("semver"));
23
+ semver = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ function _componentVersion() {
29
+ const data = require("@teambit/component-version");
30
+ _componentVersion = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _bitError() {
36
+ const data = require("@teambit/bit-error");
37
+ _bitError = function () {
38
+ return data;
39
+ };
40
+ return data;
41
+ }
42
+ function _laneId() {
43
+ const data = require("@teambit/lane-id");
44
+ _laneId = function () {
45
+ return data;
46
+ };
47
+ return data;
48
+ }
49
+ function _componentId() {
50
+ const data = require("@teambit/component-id");
51
+ _componentId = function () {
52
+ return data;
53
+ };
54
+ return data;
55
+ }
56
+ function _pMapSeries() {
57
+ const data = _interopRequireDefault(require("p-map-series"));
58
+ _pMapSeries = function () {
59
+ return data;
60
+ };
61
+ return data;
62
+ }
63
+ function _toolboxPromise() {
64
+ const data = require("@teambit/toolbox.promise.map-pool");
65
+ _toolboxPromise = function () {
66
+ return data;
67
+ };
68
+ return data;
69
+ }
70
+ function _harmonyModules() {
71
+ const data = require("@teambit/harmony.modules.concurrency");
72
+ _harmonyModules = function () {
73
+ return data;
74
+ };
75
+ return data;
76
+ }
77
+ function _toolboxArray() {
78
+ const data = require("@teambit/toolbox.array.duplications-finder");
79
+ _toolboxArray = function () {
80
+ return data;
81
+ };
82
+ return data;
83
+ }
84
+ function _legacyBitId() {
85
+ const data = require("@teambit/legacy-bit-id");
86
+ _legacyBitId = function () {
87
+ return data;
88
+ };
89
+ return data;
90
+ }
91
+ function _legacy() {
92
+ const data = require("@teambit/legacy.constants");
93
+ _legacy = function () {
94
+ return data;
95
+ };
96
+ return data;
97
+ }
98
+ function _legacy2() {
99
+ const data = require("@teambit/legacy.consumer-component");
100
+ _legacy2 = function () {
101
+ return data;
102
+ };
103
+ return data;
104
+ }
105
+ function _component() {
106
+ const data = require("@teambit/component.sources");
107
+ _component = function () {
108
+ return data;
109
+ };
110
+ return data;
111
+ }
112
+ function _legacy3() {
113
+ const data = require("@teambit/legacy.consumer-config");
114
+ _legacy3 = function () {
115
+ return data;
116
+ };
117
+ return data;
118
+ }
119
+ function _legacyCli() {
120
+ const data = require("@teambit/legacy.cli.error");
121
+ _legacyCli = function () {
122
+ return data;
123
+ };
124
+ return data;
125
+ }
126
+ function _legacy4() {
127
+ const data = require("@teambit/legacy.logger");
128
+ _legacy4 = function () {
129
+ return data;
130
+ };
131
+ return data;
132
+ }
133
+ function _legacy5() {
134
+ const data = require("@teambit/legacy.utils");
135
+ _legacy5 = function () {
136
+ return data;
137
+ };
138
+ return data;
139
+ }
140
+ function _pkgModules() {
141
+ const data = require("@teambit/pkg.modules.semver-helper");
142
+ _pkgModules = function () {
143
+ return data;
144
+ };
145
+ return data;
146
+ }
147
+ function _component2() {
148
+ const data = require("@teambit/component.snap-distance");
149
+ _component2 = function () {
150
+ return data;
151
+ };
152
+ return data;
153
+ }
154
+ function _legacy6() {
155
+ const data = require("@teambit/legacy.scope");
156
+ _legacy6 = function () {
157
+ return data;
158
+ };
159
+ return data;
160
+ }
161
+ function _objects() {
162
+ const data = require("../objects");
163
+ _objects = function () {
164
+ return data;
165
+ };
166
+ return data;
167
+ }
168
+ function _scopeMeta() {
169
+ const data = _interopRequireDefault(require("./scopeMeta"));
170
+ _scopeMeta = function () {
171
+ return data;
172
+ };
173
+ return data;
174
+ }
175
+ function _versionHistory() {
176
+ const data = _interopRequireDefault(require("./version-history"));
177
+ _versionHistory = function () {
178
+ return data;
179
+ };
180
+ return data;
181
+ }
182
+ function _detachHeads() {
183
+ const data = require("./detach-heads");
184
+ _detachHeads = function () {
185
+ return data;
186
+ };
187
+ return data;
188
+ }
189
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
190
+ 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); }
191
+ 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; }
192
+ 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; }
193
+ 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; }
194
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
195
+ 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); }
196
+ const VERSION_ZERO = exports.VERSION_ZERO = '0.0.0';
197
+
198
+ /**
199
+ * we can't rename the class as ModelComponent because old components are already saved in the model
200
+ * with 'Component' in their headers. see object-registrar.types()
201
+ */
202
+ // TODO: FIX me .parser
203
+ class Component extends _objects().BitObject {
204
+ constructor(props) {
205
+ super();
206
+ _defineProperty(this, "scope", void 0);
207
+ _defineProperty(this, "name", void 0);
208
+ _defineProperty(this, "versions", void 0);
209
+ _defineProperty(this, "orphanedVersions", void 0);
210
+ _defineProperty(this, "lang", void 0);
211
+ /**
212
+ * @deprecated moved to the Version object inside teambit/deprecation aspect
213
+ */
214
+ _defineProperty(this, "deprecated", void 0);
215
+ _defineProperty(this, "bindingPrefix", void 0);
216
+ /**
217
+ * @deprecated since 0.12.6 (long long ago :) probably can be removed)
218
+ */
219
+ _defineProperty(this, "local", void 0);
220
+ _defineProperty(this, "state", void 0);
221
+ _defineProperty(this, "scopesList", void 0);
222
+ _defineProperty(this, "head", void 0);
223
+ _defineProperty(this, "remoteHead", void 0);
224
+ // doesn't get saved in the scope, used to easier access the remote main head
225
+ /**
226
+ * doesn't get saved in the scope, used to easier access the local snap head data
227
+ * when checked out to a lane, this prop is either Ref or null. otherwise (when on main), this prop is undefined.
228
+ */
229
+ _defineProperty(this, "laneHeadLocal", void 0);
230
+ /**
231
+ * doesn't get saved in the scope, used to easier access the remote snap head data
232
+ * when checked out to a lane, this prop is either Ref or null. otherwise (when on main), this prop is undefined.
233
+ */
234
+ _defineProperty(this, "laneHeadRemote", void 0);
235
+ /**
236
+ * when checked out to a lane, calculate what should be the head on the remote.
237
+ * if the laneHeadRemote is null, for example, when the lane is new, then used the the lane it was forked from.
238
+ * it no head is found on the lane/forked, then use the component.head.
239
+ */
240
+ _defineProperty(this, "calculatedRemoteHeadWhenOnLane", void 0);
241
+ _defineProperty(this, "laneId", void 0);
242
+ // doesn't get saved in the scope.
243
+ _defineProperty(this, "laneDataIsPopulated", false);
244
+ // doesn't get saved in the scope, used to improve performance of loading the lane data
245
+ _defineProperty(this, "schema", void 0);
246
+ _defineProperty(this, "detachedHeads", void 0);
247
+ _defineProperty(this, "divergeData", void 0);
248
+ _defineProperty(this, "_populateVersionHistoryMutex", void 0);
249
+ if (!props.name) throw new TypeError('Model Component constructor expects to get a name parameter');
250
+ if (!props.scope) {
251
+ throw new (_legacy6().BitIdCompIdError)(props.name);
252
+ }
253
+ this.scope = props.scope;
254
+ this.name = props.name;
255
+ this.versions = props.versions || {};
256
+ this.orphanedVersions = props.orphanedVersions || {};
257
+ this.lang = props.lang || _legacy().DEFAULT_LANGUAGE;
258
+ this.deprecated = props.deprecated || false;
259
+ this.bindingPrefix = props.bindingPrefix || (0, _legacy3().getBindingPrefixByDefaultScope)(props.scope);
260
+ this.state = props.state || {};
261
+ this.scopesList = props.scopesList || [];
262
+ this.head = props.head;
263
+ this.schema = props.schema;
264
+ this.detachedHeads = props.detachedHeads || new (_detachHeads().DetachedHeads)();
265
+ }
266
+ get populateVersionHistoryMutex() {
267
+ if (!this._populateVersionHistoryMutex) {
268
+ this._populateVersionHistoryMutex = new (_asyncMutex().Mutex)();
269
+ }
270
+ return this._populateVersionHistoryMutex;
271
+ }
272
+ get versionArray() {
273
+ return Object.values(this.versions);
274
+ }
275
+ setVersion(tag, ref) {
276
+ this.versions[tag] = ref;
277
+ delete this.orphanedVersions[tag]; // just in case it's there.
278
+ }
279
+ setOrphanedVersion(tag, ref) {
280
+ if (this.versions[tag]) {
281
+ throw new Error(`unable to save orphanedVersion "${tag}" for "${this.id()}" because this tag is already part of the versions prop`);
282
+ }
283
+ this.orphanedVersions[tag] = ref;
284
+ }
285
+ getRef(version) {
286
+ if ((0, _componentVersion().isTag)(version)) {
287
+ return this.versionsIncludeOrphaned[version];
288
+ }
289
+ if ((0, _componentVersion().isHash)(version)) {
290
+ return new (_objects().Ref)(version);
291
+ }
292
+ return null;
293
+ }
294
+ getHeadStr() {
295
+ return this.head ? this.head.toString() : null;
296
+ }
297
+ getHead() {
298
+ return this.head;
299
+ }
300
+
301
+ /**
302
+ * returns the head hash. regardless of whether current lane is the default or not.
303
+ * if on a lane, it returns the head of the component on the lane.
304
+ */
305
+ getHeadRegardlessOfLane() {
306
+ return this.laneHeadLocal || this.getHead();
307
+ }
308
+ getHeadAsTagIfExist() {
309
+ if (!this.head) return undefined;
310
+ return this.getTagOfRefIfExists(this.head) || this.head.toString();
311
+ }
312
+ hasHead() {
313
+ return Boolean(this.head);
314
+ }
315
+ setHead(head) {
316
+ this.head = head;
317
+ }
318
+ listVersions(sort) {
319
+ const versions = Object.keys(this.versions);
320
+ if (!sort) return versions;
321
+ if (sort === 'ASC') {
322
+ return versions.sort(semver().compare);
323
+ }
324
+ return versions.sort(semver().compare).reverse();
325
+ }
326
+ listVersionsIncludeOrphaned(sort) {
327
+ const versions = Object.keys(this.versionsIncludeOrphaned);
328
+ if (!sort) return versions;
329
+ if (sort === 'ASC') {
330
+ return versions.sort(semver().compare);
331
+ }
332
+ return versions.sort(semver().compare).reverse();
333
+ }
334
+ async hasVersion(version, repo, includeOrphaned = true) {
335
+ if ((0, _componentVersion().isTag)(version)) {
336
+ return includeOrphaned ? this.hasTagIncludeOrphaned(version) : this.hasTag(version);
337
+ }
338
+ const head = this.getHeadRegardlessOfLane();
339
+ if (!head) {
340
+ return false;
341
+ }
342
+ const versionParents = await (0, _component2().getAllVersionParents)({
343
+ repo,
344
+ modelComponent: this,
345
+ heads: [head]
346
+ });
347
+ // we use "startsWith" because it can be a short hash
348
+ return versionParents.map(v => v.hash).some(hash => hash.toString().startsWith(version));
349
+ }
350
+ hasTag(version) {
351
+ return Boolean(this.versions[version]);
352
+ }
353
+ get versionsIncludeOrphaned() {
354
+ // for bit-bin with 266 components, it takes about 1,700ms. don't use lodash.merge, it's much faster
355
+ // but mutates `this.versions`.
356
+ return _objectSpread(_objectSpread({}, this.versions), this.orphanedVersions);
357
+ }
358
+ hasTagIncludeOrphaned(version) {
359
+ return Boolean(this.versions[version] || this.orphanedVersions[version]);
360
+ }
361
+
362
+ /**
363
+ * whether the head is a snap (not a tag)
364
+ */
365
+ isHeadSnap() {
366
+ const tagsHashes = this.versionArray.map(ref => ref.toString());
367
+ return this.head && !tagsHashes.includes(this.head.toString());
368
+ }
369
+
370
+ /**
371
+ * add a new remote if it is not there already
372
+ */
373
+ addScopeListItem(scopeListItem) {
374
+ if (!scopeListItem.name || !scopeListItem.url || !scopeListItem.date) {
375
+ throw new TypeError(`model-component.addRemote get an invalid remote. name: ${scopeListItem.name}, url: ${scopeListItem.url}, date: ${scopeListItem.date}`);
376
+ }
377
+ if (!this.scopesList.find(r => r.url === scopeListItem.url)) {
378
+ this.scopesList.push(scopeListItem);
379
+ }
380
+ }
381
+
382
+ /**
383
+ * on main - it checks local-head (or .bitmap version if given) vs remote-head.
384
+ * on lane - it checks local-head on lane vs remote-head on lane.
385
+ * however, to get an accurate `divergeData.snapsOnSourceOnly`, the above is not enough.
386
+ * for example, comp-a@snap-x from lane-a is merged into lane-b. we don't want this snap-x to be "local", because
387
+ * then, bit-status will show it as "staged" and bit-reset will remove it unexpectedly.
388
+ * if we only check by the local-head and remote-head on lane, it'll be local because the remote-head of lane-b is empty.
389
+ * to address this, we search all remote-refs files for this bit-id and during the local history traversal, if a hash
390
+ * is found there, it'll stop the traversal and not mark it as remote.
391
+ * in this example, during the merge, lane-a was fetched, and the remote-ref of this lane has snap-x as the head.
392
+ */
393
+ async setDivergeData(repo, throws = true, fromCache = true, workspaceId) {
394
+ if (!this.divergeData || !fromCache) {
395
+ const remoteHead = (this.laneId ? this.calculatedRemoteHeadWhenOnLane : this.remoteHead) || null;
396
+ // this is for detach-head scenario. it can happen on main only. we want to compare against the .bitmap
397
+ // version (which is the detached head) and not the actual head.
398
+ const workspaceVersion = !this.isOnLane() && workspaceId?.hasVersion() ? workspaceId.version : null;
399
+ this.divergeData = await (0, _component2().getDivergeData)({
400
+ repo,
401
+ modelComponent: this,
402
+ targetHead: remoteHead,
403
+ sourceHead: workspaceVersion ? this.getRef(workspaceVersion) : undefined,
404
+ throws
405
+ });
406
+ }
407
+ }
408
+ isOnLane() {
409
+ return Boolean(this.laneHeadLocal || this.laneHeadLocal === null);
410
+ }
411
+
412
+ /**
413
+ * this is used (among others) by `bit status` to check whether snaps are local (staged), for `bit reset` to remove them
414
+ * and for `bit export` to push them. for "merge pending" status, use `this.getDivergeDataForMergePending()`.
415
+ */
416
+ getDivergeData() {
417
+ if (!this.divergeData) throw new Error(`getDivergeData() expects divergeData to be populate, please use this.setDivergeData() for id: ${this.id()}`);
418
+ return this.divergeData;
419
+ }
420
+
421
+ /**
422
+ * don't use modelComponent.getDivergeData() because in some scenarios when on a lane, it compares the head
423
+ * on the lane against the head on the main, which could show the component as diverged incorrectly.
424
+ */
425
+ async getDivergeDataForMergePending(repo) {
426
+ return (0, _component2().getDivergeData)({
427
+ repo,
428
+ modelComponent: this,
429
+ targetHead: (this.laneId ? this.laneHeadRemote : this.remoteHead) || null,
430
+ throws: false
431
+ });
432
+ }
433
+ async populateLocalAndRemoteHeads(repo, lane) {
434
+ this.setLaneHeadLocal(lane);
435
+ if (lane) this.laneId = lane.toLaneId();
436
+ if (!this.scope) {
437
+ return; // no remote to update. it's local.
438
+ }
439
+ this.remoteHead = await repo.remoteLanes.getRef(_laneId().LaneId.from(_laneId().DEFAULT_LANE, this.scope), this.toComponentId());
440
+ if (!lane) {
441
+ return;
442
+ }
443
+ this.laneHeadRemote = lane.isNew ? null : await repo.remoteLanes.getRef(lane.toLaneId(), this.toComponentId());
444
+ const calculateRemote = async () => {
445
+ if (this.laneHeadRemote) return this.laneHeadRemote;
446
+ if (lane.isNew && lane.forkedFrom) {
447
+ // For any forked lane — same-scope or cross-scope (e.g. after `bit lane change-scope`) — use
448
+ // the forked-from lane's head as the divergence baseline. The consumer has that ref locally
449
+ // from when they ran `bit lane import` on the original lane. This is correct for both:
450
+ // - same-scope forks: identical to the previous behavior.
451
+ // - cross-scope forks: previously fell through to `this.remoteHead || this.head`, which can
452
+ // crash with `TargetHeadNotFound` when the component's main-head Version isn't local
453
+ // (common after a lean-lane import since main history doesn't live on the lane scope).
454
+ // Returning the fork's head instead reports only true local snaps as staged — not the
455
+ // entire history — which also keeps `bit reset` from over-removing.
456
+ const headFromFork = await repo.remoteLanes.getRef(lane.forkedFrom, this.toComponentId());
457
+ if (headFromFork) return headFromFork;
458
+ if (lane.forkedFrom.scope !== lane.scope) {
459
+ // Cross-scope fork and the forked-from ref isn't local. Returning null over-reports
460
+ // the lane history as staged (divergence has no baseline), but falling through to
461
+ // `this.remoteHead || this.head` would crash with TargetHeadNotFound when the main-
462
+ // head Version is missing locally. The user can recover by running `bit lane fetch`
463
+ // on the forked-from lane to populate the ref.
464
+ return null;
465
+ }
466
+ // Same-scope fork without a fork ref — fall through to the standard fallback below.
467
+ }
468
+ // if no remote-ref was found, because it's checked out to a lane, it's safe to assume that
469
+ // this.head should be on the original-remote. hence, FetchMissingHistory will retrieve it on lane-remote
470
+ return this.remoteHead || this.head;
471
+ };
472
+ this.calculatedRemoteHeadWhenOnLane = await calculateRemote();
473
+ }
474
+ setLaneHeadLocal(lane) {
475
+ if (lane) {
476
+ // include lane.updateDependents — hidden cascade entries need a lane-local head so the
477
+ // export-pending detector picks them up after a workspace cascade snap.
478
+ this.laneHeadLocal = lane.getCompHeadIncludeUpdateDependents(this.toComponentId()) || null;
479
+ }
480
+ }
481
+
482
+ /**
483
+ * returns only the versions that exist in both components (regardless whether the hash are the same)
484
+ * e.g. this.component = [0.0.1, 0.0.2, 0.0.3], other component = [0.0.3, 0.0.4]. it returns only [0.0.3].
485
+ * also, in case it is coming from 'bit import', the version must be locally changed.
486
+ * otherwise, it doesn't matter whether the hashes are different.
487
+ */
488
+ _getComparableVersionsObjects(otherComponent,
489
+ // in case of merging, the otherComponent is the existing component, and "this" is the incoming component
490
+ local) {
491
+ const otherLocalVersion = otherComponent.getLocalVersions();
492
+ const otherComponentVersions = (0, _lodash().pickBy)(otherComponent.versions, (val, key) => Object.keys(this.versions).includes(key) && (!local || otherLocalVersion.includes(key)));
493
+ const thisComponentVersions = (0, _lodash().pickBy)(this.versions, (val, key) => Object.keys(otherComponentVersions).includes(key) && (!local || otherLocalVersion.includes(key)));
494
+ return {
495
+ thisComponentVersions,
496
+ otherComponentVersions
497
+ };
498
+ }
499
+ compatibleWith(component, local) {
500
+ const {
501
+ thisComponentVersions,
502
+ otherComponentVersions
503
+ } = this._getComparableVersionsObjects(component, local);
504
+ return (0, _lodash().isEqual)(thisComponentVersions, otherComponentVersions);
505
+ }
506
+ diffWith(component, local) {
507
+ const {
508
+ thisComponentVersions,
509
+ otherComponentVersions
510
+ } = this._getComparableVersionsObjects(component, local);
511
+ return Object.keys(thisComponentVersions).filter(version => thisComponentVersions[version].hash !== otherComponentVersions[version].hash);
512
+ }
513
+ isEmpty() {
514
+ return (0, _lodash().isEmpty)(this.versions) && !this.hasHead();
515
+ }
516
+
517
+ /**
518
+ * on main return main head, on lane, return lane head.
519
+ * if the head is also a tag, return the tag, otherwise, return the hash.
520
+ */
521
+ getHeadRegardlessOfLaneAsTagOrHash(returnVersionZeroForNoHead = false) {
522
+ const head = this.getHeadRegardlessOfLane();
523
+ if (!head) {
524
+ if (!(0, _lodash().isEmpty)(this.versions)) throw new Error(`error: ${this.id()} has tags but no head, it might be originated from legacy`);
525
+ if (returnVersionZeroForNoHead) return VERSION_ZERO;
526
+ throw new Error(`getHeadRegardlessOfLaneAsTagOrHash() failed finding a head for ${this.id()}`);
527
+ }
528
+ return this.getTagOfRefIfExists(head) || head.toString();
529
+ }
530
+
531
+ /**
532
+ * get the recent head. if locally is ahead, return the local head. otherwise, return the remote head.
533
+ *
534
+ * a user can be checked out to a lane, in which case, `this.laneHeadLocal` and `this.laneHeadRemote`
535
+ * may be populated.
536
+ * `this.head` may not be populated, e.g. when a component was created on
537
+ * this lane and never got snapped on main.
538
+ * it's impossible that `this.head.isEqual(this.laneHeadLocal)`, because when snapping it's either
539
+ * on main, which goes to this.head OR on a lane, which goes to this.laneHeadLocal.
540
+ */
541
+ async headIncludeRemote(repo) {
542
+ const latestLocally = this.getHeadRegardlessOfLaneAsTagOrHash(true);
543
+ const remoteHead = this.laneHeadRemote || this.remoteHead;
544
+ if (!remoteHead) return latestLocally;
545
+ if (!this.getHeadRegardlessOfLane()) {
546
+ return remoteHead.toString(); // in case a snap was created on another lane
547
+ }
548
+
549
+ // either a user is on main or a lane, check whether the remote is ahead of the local
550
+ if (this.laneId && !this.laneHeadRemote) {
551
+ // when on a lane, setDivergeData is using the `this.calculatedRemoteHeadWhenOnLane`,
552
+ // which takes into account main-head and forked-head. here, we don't want this. we care only about the
553
+ // remote-lane head.
554
+ return latestLocally;
555
+ }
556
+ await this.setDivergeData(repo, false);
557
+ const divergeData = this.getDivergeData();
558
+ if (divergeData.isTargetAhead()) {
559
+ return this.getTagOfRefIfExists(remoteHead) || remoteHead.toString();
560
+ }
561
+ return latestLocally;
562
+ }
563
+ async getRefOfAncestor(repo, generationsToGoBack) {
564
+ const head = this.getHeadRegardlessOfLane();
565
+ if (!head) throw new (_bitError().BitError)(`getRefOfAncestor failed to find the head of ${this.id()}`);
566
+ const versionHistory = await this.getAndPopulateVersionHistory(repo, head);
567
+ return versionHistory.getAncestor(generationsToGoBack, head);
568
+ }
569
+ latestVersion() {
570
+ if ((0, _lodash().isEmpty)(this.versions)) return VERSION_ZERO;
571
+ return (0, _pkgModules().getLatestVersion)(this.listVersions());
572
+ }
573
+ latestVersionIfExist() {
574
+ if ((0, _lodash().isEmpty)(this.versions)) return undefined;
575
+ return (0, _pkgModules().getLatestVersion)(this.listVersions());
576
+ }
577
+
578
+ // @todo: make it readable, it's a mess
579
+ isLatestGreaterThan(version) {
580
+ if (!version) throw TypeError('isLatestGreaterThan expect to get a Version');
581
+ const latest = this.getHeadRegardlessOfLaneAsTagOrHash(true);
582
+ if (this.isEmpty() && !this.calculatedRemoteHeadWhenOnLane) {
583
+ return false; // in case a snap was created on another lane
584
+ }
585
+ if ((0, _componentVersion().isTag)(latest) && (0, _componentVersion().isTag)(version)) {
586
+ return semver().gt(latest, version);
587
+ }
588
+ if (latest === version) return false;
589
+ const latestRef = this.getRef(latest);
590
+ if (!latestRef) throw new Error('isLatestGreaterThan, latestRef was not found');
591
+ const latestHash = latestRef.toString();
592
+ const versionRef = this.getRef(version);
593
+ if (!versionRef) return true; // probably a child
594
+ const versionHash = versionRef.toString();
595
+ if (latestHash === versionHash) return false;
596
+ return true;
597
+ }
598
+
599
+ /**
600
+ * Return the lateset version which actuall exists in the scope
601
+ * (exists means the object itself exists)
602
+ * This relevant for cases when the component version array has few versions
603
+ * but we don't have all the refs in the object
604
+ *
605
+ * @returns {number}
606
+ * @memberof Component
607
+ */
608
+ latestExisting(repository) {
609
+ if ((0, _lodash().isEmpty)(this.versions)) return VERSION_ZERO;
610
+ const versions = this.listVersions('ASC');
611
+ let version = null;
612
+ let versionStr = null;
613
+ while (!version && versions && versions.length) {
614
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
615
+ versionStr = versions.pop();
616
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
617
+ version = this.loadVersionSync(versionStr, repository, false);
618
+ }
619
+ return versionStr || VERSION_ZERO;
620
+ }
621
+
622
+ /**
623
+ * get component log and sort by the timestamp in ascending order (from the earliest to the latest)
624
+ */
625
+ async collectLogs(scope, shortHash = false, startFrom) {
626
+ const repo = scope.objects;
627
+ let versionsInfo = await (0, _component2().getAllVersionsInfo)({
628
+ modelComponent: this,
629
+ repo,
630
+ throws: false,
631
+ startFrom
632
+ });
633
+
634
+ // due to recent changes of getting version-history object rather than fetching the entire history, some version
635
+ // objects might be missing. import the component from the remote
636
+ if (versionsInfo.some(v => v.error && (0, _legacy6().errorIsTypeOfMissingObject)(v.error)) && this.scope !== repo.scopeJson.name) {
637
+ _legacy4().logger.info(`collectLogs is unable to find some objects for ${this.id()}. will try to import them`);
638
+ try {
639
+ const lane = await scope.getCurrentLaneObject();
640
+ await scope.scopeImporter.importWithoutDeps(_componentId().ComponentIdList.fromArray([this.toComponentId()]).toVersionLatest(), {
641
+ cache: false,
642
+ includeVersionHistory: true,
643
+ collectParents: true,
644
+ lane: lane || undefined,
645
+ reason: 'to collect logs (including parents)'
646
+ });
647
+ versionsInfo = await (0, _component2().getAllVersionsInfo)({
648
+ modelComponent: this,
649
+ repo,
650
+ throws: false,
651
+ startFrom
652
+ });
653
+ // Lean-lane-scope fallback: if the lane is on a different scope from the component's
654
+ // home scope (e.g. a feature lane for a component that lives on main in another scope),
655
+ // older main snaps may not be on the lane scope. Re-fetch without lane so the fetcher
656
+ // routes to the component's home scope and brings in the missing main history.
657
+ if (lane && lane.scope !== this.scope && versionsInfo.some(v => v.error && (0, _legacy6().errorIsTypeOfMissingObject)(v.error))) {
658
+ await scope.scopeImporter.importWithoutDeps(_componentId().ComponentIdList.fromArray([this.toComponentId()]).toVersionLatest(), {
659
+ cache: false,
660
+ includeVersionHistory: true,
661
+ collectParents: true,
662
+ reason: 'to collect logs from component home scope (lean-lane-scope fallback)'
663
+ });
664
+ versionsInfo = await (0, _component2().getAllVersionsInfo)({
665
+ modelComponent: this,
666
+ repo,
667
+ throws: false,
668
+ startFrom
669
+ });
670
+ }
671
+ } catch (err) {
672
+ _legacy4().logger.error(`collectLogs failed to import ${this.id()} history`, err);
673
+ }
674
+ }
675
+ const head = this.getHeadRegardlessOfLane();
676
+ const headVersion = head ? await repo.load(head) : undefined;
677
+ const removeAspect = headVersion?.extensions.findCoreExtension(_legacy().Extensions.remove);
678
+ const removeRange = removeAspect?.config.range;
679
+ const removeSnaps = removeAspect?.config.snaps || [];
680
+ const deprecationAspect = headVersion?.extensions.findCoreExtension(_legacy().Extensions.deprecation);
681
+ const deprecationRange = deprecationAspect?.config.range;
682
+ const getRef = ref => shortHash ? ref.toShortString() : ref.toString();
683
+ const results = versionsInfo.map(versionInfo => {
684
+ const log = versionInfo.version ? versionInfo.version.log : {
685
+ message: '<no-data-available>'
686
+ };
687
+ return _objectSpread(_objectSpread({}, log), {}, {
688
+ // @ts-ignore
689
+ username: log?.username || 'unknown',
690
+ // @ts-ignore
691
+ email: log?.email || 'unknown',
692
+ tag: versionInfo.tag,
693
+ hash: getRef(versionInfo.ref),
694
+ parents: versionInfo.parents.map(parent => getRef(parent)),
695
+ onLane: versionInfo.onLane,
696
+ deleted: versionInfo.tag && removeRange && semver().satisfies(versionInfo.tag, removeRange) || !versionInfo.tag && removeSnaps.includes(versionInfo.ref.toString()),
697
+ deprecated: versionInfo.tag && deprecationRange && semver().satisfies(versionInfo.tag, deprecationRange),
698
+ hidden: versionInfo.version?.hidden
699
+ });
700
+ });
701
+ // sort from earliest to latest
702
+ const sorted = results.sort((a, b) => {
703
+ // @ts-ignore
704
+ if (a.date && b.date) return a.date - b.date;
705
+ return 0;
706
+ });
707
+ return sorted;
708
+ }
709
+ collectVersions(repo) {
710
+ return Promise.all(this.listVersions().map(versionNum => {
711
+ return this.toConsumerComponent(versionNum, this.scope, repo);
712
+ }));
713
+ }
714
+ getTagOfRefIfExists(ref, allTags = this.versionsIncludeOrphaned) {
715
+ return Object.keys(allTags).find(versionRef => allTags[versionRef].isEqual(ref));
716
+ }
717
+ getTag(version) {
718
+ if ((0, _componentVersion().isTag)(version)) return version;
719
+ const ref = _objects().Ref.from(version);
720
+ return this.getTagOfRefIfExists(ref);
721
+ }
722
+ switchHashesWithTagsIfExist(refs) {
723
+ // cache the this.versionsIncludeOrphaned results into "allTags", looks strange but it improved
724
+ // the performance on bit-bin with 188 components during source.merge in 4 seconds.
725
+ const allTags = this.versionsIncludeOrphaned;
726
+ return refs.map(ref => this.getTagOfRefIfExists(ref, allTags) || ref.toString());
727
+ }
728
+
729
+ /**
730
+ * if exactVersion is defined, add exact version instead of using the semver mechanism
731
+ */
732
+ getVersionToAdd(releaseType = _legacy().DEFAULT_BIT_RELEASE_TYPE, exactVersion, incrementBy, preReleaseId) {
733
+ if (exactVersion && this.versions[exactVersion]) {
734
+ throw new (_legacy6().VersionAlreadyExists)(exactVersion, this.id());
735
+ }
736
+ const version = exactVersion || this.version(releaseType, incrementBy, preReleaseId);
737
+ (0, _pkgModules().validateVersion)(version);
738
+ return version;
739
+ }
740
+ isEqual(component, considerOrphanedVersions = true) {
741
+ if (this.hasHead() && !component.hasHead() || !this.hasHead() && component.hasHead()) {
742
+ return false; // only one of them has head
743
+ }
744
+ if (this.head && component.head && !this.head.isEqual(component.head)) {
745
+ return false; // the head is not equal.
746
+ }
747
+ // the head is equal or they both don't have head. check the versions
748
+ if (this.versionArray.length !== component.versionArray.length) {
749
+ return false;
750
+ }
751
+ const hasSameVersions = Object.keys(this.versions).every(tag => component.versions[tag] && component.versions[tag].isEqual(this.versions[tag]));
752
+ if (considerOrphanedVersions) {
753
+ if (Object.keys(this.orphanedVersions).length !== Object.keys(component.orphanedVersions).length) {
754
+ return false;
755
+ }
756
+ const hasSameOrphanedVersions = Object.keys(this.orphanedVersions).every(tag => component.orphanedVersions[tag] && component.orphanedVersions[tag].isEqual(this.orphanedVersions[tag]));
757
+ if (!hasSameOrphanedVersions) {
758
+ return false;
759
+ }
760
+ }
761
+ return hasSameVersions;
762
+ }
763
+
764
+ // eslint-disable-next-line complexity
765
+ addVersion(version, versionToAdd, lane, previouslyUsedVersion, {
766
+ addToUpdateDependentsInLane,
767
+ setHeadAsParent,
768
+ detachHead,
769
+ overrideHead
770
+ } = {}) {
771
+ if (detachHead && overrideHead) {
772
+ throw new Error(`addVersion expects either detachHead or overrideHead to be true, not both`);
773
+ }
774
+ if (lane) {
775
+ if ((0, _componentVersion().isTag)(versionToAdd)) {
776
+ throw new (_bitError().BitError)('unable to tag when checked out to a lane, please switch to main, merge the lane and then tag again');
777
+ }
778
+ const currentBitId = this.toComponentId();
779
+ const versionToAddRef = _objects().Ref.from(versionToAdd);
780
+ const parent = previouslyUsedVersion ? this.getRef(previouslyUsedVersion) : null;
781
+ if (!parent) {
782
+ const existingComponentInLane = lane.getComponent(currentBitId);
783
+ const currentHead = existingComponentInLane && existingComponentInLane.head || this.getHead();
784
+ if (currentHead) {
785
+ throw new Error(`component ${currentBitId.toString()} has a head (${currentHead.toString()}) but previouslyUsedVersion is empty`);
786
+ }
787
+ }
788
+ if (parent && !parent.isEqual(versionToAddRef)) {
789
+ version.addAsOnlyParent(parent);
790
+ }
791
+ // When the caller didn't explicitly opt in or out, preserve the existing entry's bucket so
792
+ // a merge-from-main producing a new snap for a hidden updateDependent keeps it hidden
793
+ // rather than promoting it into workspace-tracked state.
794
+ const existingHidden = lane.findUpdateDependent(currentBitId);
795
+ const existingVisible = lane.getComponent(currentBitId);
796
+ const shouldBeHidden = addToUpdateDependentsInLane ?? (Boolean(existingHidden) && !existingVisible);
797
+ if (shouldBeHidden) {
798
+ if (existingVisible) lane.removeComponent(currentBitId);
799
+ lane.addComponentToUpdateDependents(currentBitId.changeVersion(versionToAddRef.toString()));
800
+ // Only brand-new hidden insertions raise the wire flag — that's the `_snap --update-dependents`
801
+ // path adding a component that wasn't already on the lane. Cascades update an existing
802
+ // hidden entry (wasAlreadyHidden=true) and must NOT raise the flag, otherwise origin would
803
+ // re-add entries the Cloud UI explicitly dropped.
804
+ if (!existingHidden) lane.setOverrideUpdateDependents(true);
805
+ } else {
806
+ if (existingHidden) lane.removeComponentFromUpdateDependentsIfExist(currentBitId);
807
+ lane.addComponent({
808
+ id: currentBitId,
809
+ head: versionToAddRef,
810
+ isDeleted: version.isRemoved()
811
+ });
812
+ }
813
+ if (lane.readmeComponent && lane.readmeComponent.id.fullName === currentBitId.fullName) {
814
+ lane.setReadmeComponent(currentBitId);
815
+ }
816
+ this.laneHeadLocal = versionToAddRef;
817
+ return versionToAdd;
818
+ }
819
+ // user on main
820
+ const head = this.getHead();
821
+ const parent = previouslyUsedVersion ? this.getRef(previouslyUsedVersion) : null;
822
+ if (head && head.toString() !== versionToAdd && !this.hasTag(versionToAdd) // happens with auto-snap
823
+ ) {
824
+ // if this is a tag and this tag exists, the same version was added before with a different hash.
825
+ // adding the current head into the parent will result in a non-exist hash in the parent.
826
+ // if this is a hash and it's the same hash as the current head, adding it as a parent
827
+ // results in a parent and a version has the same hash.
828
+ // @todo: fix it in a more elegant way
829
+ const parentToSet = setHeadAsParent ? head : parent;
830
+ version.addAsOnlyParent(parentToSet || head);
831
+ }
832
+ if (parent && head && !parent.isEqual(head) && !overrideHead) {
833
+ if (detachHead) this.detachedHeads.setHead(version.hash());else throw new Error(`unable to add a new version for "${this.id()}" on main.
834
+ this version started from an older version (${previouslyUsedVersion}), and not from the head (${head}).
835
+ please run "bit checkout head" to be up to date, then snap/tag your changes.
836
+ if this is done intentionally, you can use --detach-head (or --override-head if available), but make sure you understand the implications as this is an experimental feature that may not be fully stable.`);
837
+ } else {
838
+ this.setHead(version.hash());
839
+ this.detachedHeads.clearCurrent();
840
+ }
841
+ if ((0, _componentVersion().isTag)(versionToAdd)) {
842
+ this.setVersion(versionToAdd, version.hash());
843
+ }
844
+ this.markVersionAsLocal(versionToAdd);
845
+ return versionToAdd;
846
+ }
847
+ version(releaseType = _legacy().DEFAULT_BIT_RELEASE_TYPE, incrementBy = 1, preReleaseId) {
848
+ const increment = ver => {
849
+ try {
850
+ // don't use "semver.inc" function, it'll swallow the error and return null.
851
+ const incResult = new (semver().SemVer)(ver).inc(releaseType, preReleaseId);
852
+ return incResult.version;
853
+ } catch (err) {
854
+ throw new Error(`unable to increment version "${ver}" with releaseType "${releaseType}" and preReleaseId "${preReleaseId}".
855
+ Error from "semver": ${err.message}`);
856
+ }
857
+ };
858
+ const latest = this.latestVersion();
859
+ if (!latest) {
860
+ const isPreReleaseLike = ['prerelease', 'premajor', 'preminor', 'prepatch'].includes(releaseType);
861
+ return isPreReleaseLike ? increment(_legacy().DEFAULT_BIT_VERSION) : _legacy().DEFAULT_BIT_VERSION;
862
+ }
863
+ let result = increment(latest);
864
+ if (incrementBy === 1) return result;
865
+ for (let i = 1; i < incrementBy; i += 1) {
866
+ result = increment(result);
867
+ }
868
+ return result;
869
+ }
870
+ id() {
871
+ return this.scope ? [this.scope, this.name].join('/') : this.name;
872
+ }
873
+
874
+ /**
875
+ * @deprecated use toComponentId() instead
876
+ */
877
+ toBitId() {
878
+ return new (_legacyBitId().BitId)({
879
+ scope: this.scope,
880
+ name: this.name
881
+ });
882
+ }
883
+ toComponentId() {
884
+ if (!this.scope) throw new Error(`ModelComponent: scope is missing from "${this.name}"`);
885
+ return new (_componentId().ComponentID)(this.toBitId());
886
+ }
887
+
888
+ /**
889
+ * @deprecated use toComponentIdWithLatestVersion() instead
890
+ */
891
+ toBitIdWithLatestVersion() {
892
+ return new (_legacyBitId().BitId)({
893
+ scope: this.scope,
894
+ name: this.name,
895
+ version: this.getHeadRegardlessOfLaneAsTagOrHash(true)
896
+ });
897
+ }
898
+ toComponentIdWithLatestVersion() {
899
+ return _componentId().ComponentID.fromObject({
900
+ scope: this.scope,
901
+ name: this.name,
902
+ version: this.getHeadRegardlessOfLaneAsTagOrHash(true)
903
+ });
904
+ }
905
+ toComponentIdWithHead() {
906
+ return _componentId().ComponentID.fromObject({
907
+ scope: this.scope,
908
+ name: this.name,
909
+ version: this.head?.toString()
910
+ });
911
+ }
912
+ toBitIdWithLatestVersionAllowNull() {
913
+ const id = this.toComponentIdWithLatestVersion();
914
+ return id.version === VERSION_ZERO ? id.changeVersion(undefined) : id;
915
+ }
916
+ toObject() {
917
+ function versions(vers) {
918
+ const obj = {};
919
+ (0, _lodash().forEach)(vers, (ref, version) => {
920
+ obj[version] = ref.toString();
921
+ });
922
+ return obj;
923
+ }
924
+ const componentObject = {
925
+ name: this.name,
926
+ scope: this.scope,
927
+ versions: versions(this.versions),
928
+ lang: this.lang,
929
+ deprecated: this.deprecated,
930
+ bindingPrefix: this.bindingPrefix,
931
+ remotes: this.scopesList,
932
+ schema: this.schema,
933
+ detachedHeads: this.detachedHeads.toObject()
934
+ };
935
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
936
+ if (this.local) componentObject.local = this.local;
937
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
938
+ if (!(0, _lodash().isEmpty)(this.state)) componentObject.state = this.state;
939
+ // @ts-ignore
940
+ if (!(0, _lodash().isEmpty)(this.orphanedVersions)) componentObject.orphanedVersions = versions(this.orphanedVersions);
941
+ const headStr = this.getHeadStr();
942
+ // @ts-ignore
943
+ if (headStr) componentObject.head = headStr;
944
+ return componentObject;
945
+ }
946
+ async loadVersion(versionStr, repository, throws = true) {
947
+ const versionRef = this.getRef(versionStr);
948
+ if (!versionRef) throw new (_legacy6().VersionNotFound)(versionStr, this.id());
949
+ const version = await repository.load(versionRef, false);
950
+ if (!version && throws) throw new (_legacy6().VersionNotFoundOnFS)(versionStr, this.id());
951
+ return version;
952
+ }
953
+ loadVersionSync(version, repository, throws = true) {
954
+ const versionRef = this.getRef(version);
955
+ if (!versionRef) throw new (_legacy6().VersionNotFound)(version, this.id());
956
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
957
+ return versionRef.loadSync(repository, throws);
958
+ }
959
+ async collectVersionsObjects(repo, versions, throwForMissingLocalArtifacts = false, workspaceId) {
960
+ const refsWithoutArtifacts = [];
961
+ const artifactsRefs = [];
962
+ const artifactsRefsFromExportedVersions = [];
963
+ const locallyChangedVersions = await this.getLocalTagsOrHashes(repo, workspaceId);
964
+ const locallyChangedHashes = locallyChangedVersions.map(v => (0, _componentVersion().isTag)(v) ? this.versionsIncludeOrphaned[v].hash : v);
965
+ const versionsRefs = versions.map(version => this.getRef(version));
966
+ refsWithoutArtifacts.push(...versionsRefs);
967
+ const versionsObjects = await Promise.all(versionsRefs.map(versionRef => this.loadVersion(versionRef.toString(), repo)));
968
+ versionsObjects.forEach(versionObject => {
969
+ const refs = versionObject.refsWithOptions(false, false);
970
+ refsWithoutArtifacts.push(...refs);
971
+ const refsFromExtensions = (0, _component().getRefsFromExtensions)(versionObject.extensions);
972
+ locallyChangedHashes.includes(versionObject.hash().toString()) ? artifactsRefs.push(...refsFromExtensions) : artifactsRefsFromExportedVersions.push(...refsFromExtensions);
973
+ });
974
+ const loadedRefs = [];
975
+ try {
976
+ const loaded = await repo.loadManyRaw(refsWithoutArtifacts);
977
+ loadedRefs.push(...loaded);
978
+ } catch (err) {
979
+ if (err.code === 'ENOENT') {
980
+ throw new Error(`unable to find an object file "${err.path}"
981
+ for a component "${this.id()}", versions: ${versions.join(', ')}`);
982
+ }
983
+ throw err;
984
+ }
985
+ try {
986
+ const loaded = throwForMissingLocalArtifacts ? await repo.loadManyRaw(artifactsRefs) : await repo.loadManyRawIgnoreMissing(artifactsRefs);
987
+ loadedRefs.push(...loaded);
988
+ // ignore missing artifacts when exporting old versions that were exported in the past and are now exported to a
989
+ // different scope. this is happening for example when exporting a lane that has components from different
990
+ // remotes. it's ok to not have all artifacts from the other remotes to this remote.
991
+ const loadedExportedArtifacts = await repo.loadManyRawIgnoreMissing(artifactsRefsFromExportedVersions);
992
+ loadedRefs.push(...loadedExportedArtifacts);
993
+ } catch (err) {
994
+ if (err.code === 'ENOENT') {
995
+ throw new Error(`unable to find an artifact object file "${err.path}"
996
+ for a component "${this.id()}", versions: ${versions.join(', ')}
997
+ consider using --ignore-missing-artifacts flag if you're sure the artifacts are in the remote`);
998
+ }
999
+ throw err;
1000
+ }
1001
+ return loadedRefs;
1002
+ }
1003
+ async collectObjects(repo) {
1004
+ try {
1005
+ const [rawComponent, objects] = await Promise.all([this.asRaw(repo), this.collectRaw(repo)]);
1006
+ return new (_legacy6().ComponentObjects)(rawComponent, objects.map(o => o.buffer));
1007
+ } catch (err) {
1008
+ if (err.code === 'ENOENT') {
1009
+ throw new Error(`fatal: an object of "${this.id()}" was not found at ${err.path}\nplease try to re-import the component`);
1010
+ }
1011
+ throw err;
1012
+ }
1013
+ }
1014
+
1015
+ /**
1016
+ * to delete a version from a component, don't call this method directly. Instead, use sources.removeVersion()
1017
+ */
1018
+ removeVersion(version) {
1019
+ const objectRef = this.getRef(version);
1020
+ if (!objectRef) throw new Error(`removeVersion failed finding version ${version}`);
1021
+ delete this.versions[version];
1022
+ if (this.state.versions && this.state.versions[version]) delete this.state.versions[version];
1023
+ return objectRef;
1024
+ }
1025
+ toComponentVersion(versionStr) {
1026
+ const versionParsed = (0, _componentVersion().versionParser)(versionStr);
1027
+ const versionNum = versionParsed.latest ? this.getHeadRegardlessOfLaneAsTagOrHash(true) : versionParsed.versionNum;
1028
+ if (versionNum === VERSION_ZERO) {
1029
+ throw new (_legacy6().NoHeadNoVersion)(this.id());
1030
+ }
1031
+ if ((0, _componentVersion().isTag)(versionNum) && !this.hasTagIncludeOrphaned(versionNum)) {
1032
+ throw new (_bitError().BitError)(`the version ${versionNum} of "${this.id()}" does not exist in ${this.listVersionsIncludeOrphaned().join('\n')}, versions array.`);
1033
+ }
1034
+ return new (_legacy6().ComponentVersion)(this, versionNum);
1035
+ }
1036
+
1037
+ /**
1038
+ * if no "specificVersion" is given, it returns according to the head
1039
+ */
1040
+ async isDeprecated(repo, specificVersion) {
1041
+ // backward compatibility
1042
+ if (this.deprecated) {
1043
+ return true;
1044
+ }
1045
+ const head = this.getHeadRegardlessOfLane();
1046
+ if (!head) {
1047
+ // it's legacy, or new. If legacy, the "deprecated" prop should do. if it's new, the workspace should
1048
+ // have the answer.
1049
+ return false;
1050
+ }
1051
+ const headVersion = await repo.load(head);
1052
+ if (!headVersion) {
1053
+ // the head Version doesn't exist locally, there is no way to know whether it's deprecated
1054
+ return null;
1055
+ }
1056
+ const deprecationAspect = headVersion.extensions.findCoreExtension(_legacy().Extensions.deprecation);
1057
+ if (!deprecationAspect) {
1058
+ return false;
1059
+ }
1060
+ if (deprecationAspect.config.deprecate) {
1061
+ return true;
1062
+ }
1063
+ if (specificVersion && deprecationAspect.config.range) {
1064
+ const tag = this.getTag(specificVersion);
1065
+ if (!tag) return false; // it's a snap. "range" doesn't support deprecating snaps. only semver.
1066
+ return semver().satisfies(tag, deprecationAspect.config.range);
1067
+ }
1068
+ return false;
1069
+ }
1070
+
1071
+ /**
1072
+ * whether the head is marked as internal. internal components are still versioned and exported,
1073
+ * but are hidden by default in the UI (workspace, scope and Bit Cloud).
1074
+ */
1075
+ async isInternal(repo) {
1076
+ const head = this.getHeadRegardlessOfLane();
1077
+ if (!head) {
1078
+ // it's new. the workspace should have the answer.
1079
+ return false;
1080
+ }
1081
+ const headVersion = await repo.load(head);
1082
+ if (!headVersion) {
1083
+ // the head Version doesn't exist locally, there is no way to know whether it's internal
1084
+ return null;
1085
+ }
1086
+ const internalizeAspect = headVersion.extensions.findCoreExtension(_legacy().Extensions.internalize);
1087
+ if (!internalizeAspect) {
1088
+ return false;
1089
+ }
1090
+ return Boolean(internalizeAspect.config.internal);
1091
+ }
1092
+ async isRemoved(repo, specificVersion) {
1093
+ const getHead = () => {
1094
+ if (!this.laneHeadLocal) return this.getHead();
1095
+ // you're checked out to a lane.
1096
+ if (!specificVersion) return this.laneHeadLocal;
1097
+ // it's possible that this specificVersion is from main.
1098
+ if (specificVersion === this.laneHeadLocal.toString()) return this.laneHeadLocal;
1099
+ return this.getHead();
1100
+ };
1101
+ const head = getHead();
1102
+ if (!head) {
1103
+ // it's new or only on lane
1104
+ return false;
1105
+ }
1106
+ const headVersion = await repo.load(head);
1107
+ if (!headVersion) {
1108
+ // the head Version doesn't exist locally, there is no way to know whether it's removed
1109
+ return null;
1110
+ }
1111
+ const removeAspect = headVersion.extensions.findCoreExtension(_legacy().Extensions.remove);
1112
+ if (!removeAspect) {
1113
+ return false;
1114
+ }
1115
+ if (removeAspect.config.removed) {
1116
+ return true;
1117
+ }
1118
+ if (specificVersion) {
1119
+ if (removeAspect.config.range) {
1120
+ const tag = this.getTag(specificVersion);
1121
+ if (tag) return semver().satisfies(tag, removeAspect.config.range);
1122
+ }
1123
+ if (removeAspect.config.snaps && Array.isArray(removeAspect.config.snaps)) {
1124
+ return removeAspect.config.snaps.includes(specificVersion);
1125
+ }
1126
+ }
1127
+ return false;
1128
+ }
1129
+ async isLaneReadmeOf(repo) {
1130
+ const head = this.getHeadRegardlessOfLane();
1131
+ if (!head) {
1132
+ // we dont support lanes in legacy
1133
+ return [];
1134
+ }
1135
+ const version = await repo.load(head);
1136
+ if (!version) {
1137
+ // the head Version doesn't exist locally, there is no way to know whether it is a lane readme component
1138
+ return [];
1139
+ }
1140
+ const lanesAspect = version.extensions.findCoreExtension(_legacy().Extensions.lanes);
1141
+ if (!lanesAspect || !lanesAspect.config.readme) {
1142
+ return [];
1143
+ }
1144
+ return Object.keys(lanesAspect.config.readme);
1145
+ }
1146
+ /**
1147
+ * convert a ModelComponent of a specific version to ConsumerComponent
1148
+ * @see sources.consumerComponentToVersion() for the opposite action.
1149
+ */
1150
+ async toConsumerComponent(versionStr, scopeName, repository) {
1151
+ _legacy4().logger.trace(`model-component, converting ${this.id()}, version: ${versionStr} to ConsumerComponent`);
1152
+ let componentVersion = this.toComponentVersion(versionStr);
1153
+ const version = await componentVersion.getVersion(repository);
1154
+ // in case the the version is a short-hash, it should be converted to a full hash.
1155
+ if (versionStr !== _componentVersion().LATEST_VERSION && !(0, _componentVersion().isTag)(versionStr) && !(0, _componentVersion().isSnap)(versionStr) && version.hash().toString() !== versionStr) {
1156
+ componentVersion = new (_legacy6().ComponentVersion)(this, version.hash().toString());
1157
+ }
1158
+ const resolvedVersion = componentVersion.version;
1159
+ const loadFileInstance = ClassName => async file => {
1160
+ const loadP = file.file.load(repository);
1161
+ const content = await loadP;
1162
+ if (!content) throw new (_bitError().BitError)(`failed loading file ${file.relativePath} (ref: ${file.file.toString()}) from the model of ${this.id()}@${resolvedVersion}.
1163
+ The Source object is missing from the local scope.
1164
+ To fix, run:
1165
+ bit import ${this.id()}@${resolvedVersion} --objects --all-history`);
1166
+ return new ClassName({
1167
+ base: '.',
1168
+ path: file.relativePath,
1169
+ contents: content.contents,
1170
+ test: file.test
1171
+ });
1172
+ };
1173
+ const filesP = version.files ? Promise.all(version.files.map(loadFileInstance(_component().SourceFile))) : null;
1174
+ // @todo: this is weird. why the scopeMeta would be taken from the current scope and not he component scope?
1175
+ const scopeMetaP = scopeName ? _scopeMeta().default.fromScopeName(scopeName).load(repository) : Promise.resolve();
1176
+ const log = version.log || null;
1177
+ const [files, scopeMeta] = await Promise.all([filesP, scopeMetaP]);
1178
+ const extensions = version.extensions.clone();
1179
+ // when generating a new ConsumerComponent out of Version, it is critical to make sure that
1180
+ // all objects are cloned and not copied by reference. Otherwise, every time the
1181
+ // ConsumerComponent instance is changed, the Version will be changed as well, and since
1182
+ // the Version instance is saved in the Repository._cache, the next time a Version instance
1183
+ // is retrieved, it'll be different than the first time.
1184
+ const consumerComponent = new (_legacy2().ConsumerComponent)({
1185
+ name: this.name,
1186
+ version: componentVersion.version,
1187
+ scope: this.toComponentId()._legacy.scope,
1188
+ defaultScope: this.scope,
1189
+ lang: this.lang,
1190
+ bindingPrefix: this.bindingPrefix,
1191
+ mainFile: version.mainFile,
1192
+ dependencies: this.addDepsInfoFromDepsResolver(version.dependencies, extensions),
1193
+ devDependencies: this.addDepsInfoFromDepsResolver(version.devDependencies, extensions),
1194
+ flattenedDependencies: version.flattenedDependencies.clone(),
1195
+ packageDependencies: (0, _lodash().clone)(version.packageDependencies),
1196
+ devPackageDependencies: (0, _lodash().clone)(version.devPackageDependencies),
1197
+ peerPackageDependencies: (0, _lodash().clone)(version.peerPackageDependencies),
1198
+ // @ts-ignore
1199
+ files,
1200
+ docs: version.docs,
1201
+ // @ts-ignore
1202
+ license: scopeMeta ? _component().License.deserialize(scopeMeta.license) : undefined,
1203
+ // todo: make sure we have license in case of local scope
1204
+ log,
1205
+ overrides: _legacy3().ComponentOverrides.loadFromScope(version.overrides),
1206
+ packageJsonChangedProps: (0, _lodash().clone)(version.packageJsonChangedProps),
1207
+ deprecated: this.deprecated,
1208
+ removed: version.isRemoved(),
1209
+ scopesList: (0, _lodash().clone)(this.scopesList),
1210
+ schema: version.schema,
1211
+ extensions,
1212
+ buildStatus: version.buildStatus
1213
+ });
1214
+ return consumerComponent;
1215
+ }
1216
+ addDepsInfoFromDepsResolver(dependencies, extensions) {
1217
+ const cloned = dependencies.getClone();
1218
+ const depsResolverData = extensions.find(ext => ext.name === 'teambit.dependencies/dependency-resolver');
1219
+ if (!depsResolverData) return cloned;
1220
+ cloned.forEach(dependency => {
1221
+ if (dependency.packageName) return;
1222
+ const matchedEntry = depsResolverData.data?.dependencies?.find(entry => {
1223
+ return dependency.id.toString() === entry.id;
1224
+ });
1225
+ if (matchedEntry) {
1226
+ dependency.packageName = matchedEntry.packageName;
1227
+ }
1228
+ });
1229
+ return cloned;
1230
+ }
1231
+
1232
+ // @todo: make sure it doesn't have the same ref twice, once as a version and once as a head
1233
+ refs() {
1234
+ const versions = Object.values(this.versionsIncludeOrphaned);
1235
+ if (this.head) versions.push(this.head);
1236
+ return versions;
1237
+ }
1238
+ validateBeforePersisting(componentStr) {
1239
+ _legacy4().logger.trace(`validating component object: ${this.hash().hash} ${this.id()}`);
1240
+ const component = Component.parse(componentStr);
1241
+ component.validate();
1242
+ }
1243
+ toBuffer(pretty) {
1244
+ const args = (0, _legacy5().getStringifyArgs)(pretty);
1245
+ const obj = this.toObject();
1246
+ const str = JSON.stringify(obj, ...args);
1247
+ if (this.validateBeforePersist) this.validateBeforePersisting(str);
1248
+ return Buffer.from(str);
1249
+ }
1250
+
1251
+ /**
1252
+ * Clear data that is relevant only for the local scope and should not be moved to the remote scope
1253
+ */
1254
+ clearStateData() {
1255
+ this.local = false; // backward compatibility for components created before 0.12.6
1256
+ this.state = {};
1257
+ }
1258
+ markVersionAsLocal(version) {
1259
+ if (!this.state.versions) this.state = {
1260
+ versions: {}
1261
+ };
1262
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
1263
+ if (!this.state.versions[version]) this.state.versions[version] = {};
1264
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
1265
+ this.state.versions[version].local = true;
1266
+ }
1267
+
1268
+ /**
1269
+ * local versions that are not exported on the main lane.
1270
+ * @see `this.getLocalTagsOrHashes()`, to get local snaps on the current lane
1271
+ */
1272
+ getLocalVersions() {
1273
+ if ((0, _lodash().isEmpty)(this.state) || (0, _lodash().isEmpty)(this.state.versions)) return [];
1274
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
1275
+ return Object.keys(this.state.versions).filter(version => this.state.versions[version].local);
1276
+ }
1277
+ hasLocalTag(tag) {
1278
+ const localVersions = this.getLocalVersions();
1279
+ return localVersions.includes(tag);
1280
+ }
1281
+ async getLocalTagsOrHashes(repo, workspaceId, lane) {
1282
+ const localHashes = await this.getLocalHashes(repo, workspaceId, lane);
1283
+ if (!localHashes.length) return [];
1284
+ return this.switchHashesWithTagsIfExist(localHashes).reverse(); // reverse to get the older first
1285
+ }
1286
+
1287
+ /**
1288
+ * Raw divergence (`snapsOnSourceOnly`). When `lane` is provided, applies the lean-lane filter:
1289
+ * drops refs whose Version is main-origin. Those refs already live on the component's home
1290
+ * scope (and on the destination too in the same-scope case), so `bit export` shouldn't be
1291
+ * re-pushing them. Pass `lane` from status/export/reset to share the same "what's actually
1292
+ * local on this lane" view.
1293
+ *
1294
+ * The lane's recorded head for this component is always kept, even if it's main-origin — the
1295
+ * lane object references it and the destination scope must be able to resolve the hash. Versions
1296
+ * marked `squashed` or `unrelated` are kept as well — they're locally-mutated and the
1297
+ * destination needs them to reconstruct the lane history.
1298
+ */
1299
+ async getLocalHashes(repo, workspaceId, lane) {
1300
+ await this.setDivergeData(repo, undefined, undefined, workspaceId);
1301
+ const divergeData = this.getDivergeData();
1302
+ const localHashes = divergeData.snapsOnSourceOnly;
1303
+
1304
+ // When there's a detached head, divergeData only includes the detached head lineage.
1305
+ // We also need to include unexported versions from the main head lineage.
1306
+ const hasDetachedHead = this.detachedHeads && this.detachedHeads.getAllHeads().length > 0;
1307
+ if (hasDetachedHead && this.head) {
1308
+ // Calculate divergence from the main head as well
1309
+ const mainHeadDivergeData = await (0, _component2().getDivergeData)({
1310
+ repo,
1311
+ modelComponent: this,
1312
+ targetHead: (this.laneId ? this.calculatedRemoteHeadWhenOnLane : this.remoteHead) || null,
1313
+ sourceHead: this.head,
1314
+ throws: false
1315
+ });
1316
+ // Add main head local versions that aren't already in localHashes
1317
+ for (const hash of mainHeadDivergeData.snapsOnSourceOnly) {
1318
+ if (!localHashes.find(h => h.isEqual(hash))) {
1319
+ localHashes.push(hash);
1320
+ }
1321
+ }
1322
+ }
1323
+ if (!localHashes.length) return [];
1324
+ const filtered = lane ? await this.filterLeanLaneRefs(repo, lane, localHashes) : localHashes;
1325
+ return filtered.reverse(); // reverse to get the older first
1326
+ }
1327
+ async filterLeanLaneRefs(repo, lane, refs) {
1328
+ const laneHead = lane.getCompHeadIncludeUpdateDependents(this.toComponentId());
1329
+ const keptRefs = await (0, _toolboxPromise().pMapPool)(refs, async ref => {
1330
+ if (laneHead && ref.isEqual(laneHead)) return ref;
1331
+ const obj = await ref.load(repo);
1332
+ if (!obj) return null;
1333
+ const isLaneOrigin = Boolean(obj.originLaneId);
1334
+ const isLocallyMutated = Boolean(obj.squashed) || Boolean(obj.unrelated);
1335
+ if (!isLaneOrigin && !isLocallyMutated) return null;
1336
+ return ref;
1337
+ }, {
1338
+ concurrency: (0, _harmonyModules().concurrentComponentsLimit)()
1339
+ });
1340
+ return keptRefs.filter(ref => ref !== null);
1341
+ }
1342
+
1343
+ /**
1344
+ * for most cases, use `isLocallyChanged`, which takes into account lanes.
1345
+ * this is for cases when we only care about the versions exist in the `state` prop.
1346
+ */
1347
+ isLocallyChangedRegardlessOfLanes() {
1348
+ return Boolean(this.getLocalVersions().length);
1349
+ }
1350
+
1351
+ /**
1352
+ * whether the component was locally changed, either by adding a new snap/tag or by merging
1353
+ * components from different lanes.
1354
+ */
1355
+ async isLocallyChanged(repo, lane, workspaceId) {
1356
+ if (lane) await this.populateLocalAndRemoteHeads(repo, lane);
1357
+ await this.setDivergeData(repo, undefined, undefined, workspaceId);
1358
+ const divergeData = this.getDivergeData();
1359
+ return divergeData.isSourceAhead();
1360
+ }
1361
+ async getVersionHistory(repo) {
1362
+ const emptyVersionHistory = _versionHistory().default.fromId(this.name, this.scope);
1363
+ const versionHistory = await repo.load(emptyVersionHistory.hash());
1364
+ return versionHistory || emptyVersionHistory;
1365
+ }
1366
+ async getAndPopulateVersionHistory(repo, head) {
1367
+ const versionHistory = await this.getVersionHistory(repo);
1368
+ const {
1369
+ err
1370
+ } = await this.populateVersionHistoryIfMissingGracefully(repo, versionHistory, head);
1371
+ if (err) {
1372
+ _legacy4().logger.error(`rethrowing an error ${err.message}, current stuck`, new Error(err.message));
1373
+ throw err;
1374
+ }
1375
+ return versionHistory;
1376
+ }
1377
+
1378
+ /**
1379
+ * careful! the `versions` passed here can belong to other components, not necessarily to this one.
1380
+ * that's why it checks whether the version-hash exists in the VersionHistory, and if it's not,
1381
+ * it won't update it.
1382
+ */
1383
+ async updateRebasedVersionHistory(repo, versions) {
1384
+ const versionHistory = await this.getVersionHistory(repo);
1385
+ const hasUpdated = versions.some(version => {
1386
+ const versionData = versionHistory.getVersionData(version.hash());
1387
+ if (!versionData) return false;
1388
+ versionHistory.addFromVersionsObjects([version]);
1389
+ return true;
1390
+ });
1391
+ return hasUpdated ? versionHistory : undefined;
1392
+ }
1393
+ async updateVersionHistory(repo, versions) {
1394
+ const versionHistory = await this.getVersionHistory(repo);
1395
+ versionHistory.addFromVersionsObjects(versions);
1396
+ _legacy4().logger.debug(`updating version history of ${this.id()} with ${versions.length} versions`);
1397
+ return versionHistory;
1398
+ }
1399
+ async populateVersionHistoryIfMissingGracefully(repo, versionHistory, head,
1400
+ /**
1401
+ * during traversal, if a hash is found in the VersionHistory it probably means that it has all history until this
1402
+ * point, so we can stop there for better performance. In some rare cases (e.g. the export was interrupted), we
1403
+ * need the ability of full traversal to repair the VersionHistory.
1404
+ */
1405
+ exitWhenFind = true) {
1406
+ const headExists = versionHistory.hasHash(head);
1407
+ if (exitWhenFind && headExists) return {};
1408
+ const getVersionObj = async ref => await ref.load(repo);
1409
+ const versionsToAdd = [];
1410
+ let err;
1411
+ const addParentsRecursively = async version => {
1412
+ await (0, _pMapSeries().default)(version.parents, async parent => {
1413
+ const foundParent = versionHistory.hasHash(parent) || versionsToAdd.find(v => v.hash().isEqual(parent));
1414
+ if (exitWhenFind && foundParent) {
1415
+ return;
1416
+ }
1417
+ const parentVersion = await getVersionObj(parent);
1418
+ if (!parentVersion) {
1419
+ const tag = this.getTagOfRefIfExists(parent);
1420
+ err = tag ? new (_legacy6().VersionNotFound)(tag, this.id()) : new (_legacy6().ParentNotFound)(this.id(), version.hash().toString(), parent.toString());
1421
+ return;
1422
+ }
1423
+ versionsToAdd.push(parentVersion);
1424
+ await addParentsRecursively(parentVersion);
1425
+ });
1426
+ };
1427
+ const headVer = await getVersionObj(head);
1428
+ if (!headVer) {
1429
+ return {
1430
+ err: new (_legacy6().HeadNotFound)(this.id(), head.toString())
1431
+ };
1432
+ }
1433
+ return this.populateVersionHistoryMutex.runExclusive(async () => {
1434
+ if (!headExists) versionsToAdd.push(headVer);
1435
+ await addParentsRecursively(headVer);
1436
+ const added = versionsToAdd.map(v => (0, _component2().getVersionParentsFromVersion)(v));
1437
+ if (err) {
1438
+ return {
1439
+ err,
1440
+ added
1441
+ };
1442
+ }
1443
+ versionHistory.addFromVersionsObjects(versionsToAdd);
1444
+ _legacy4().logger.debug(`populateVersionHistoryIfMissingGracefully, updating ${this.id()} with ${versionsToAdd.length} versions`);
1445
+ await repo.writeObjectsToTheFS([versionHistory]);
1446
+ return {
1447
+ added
1448
+ };
1449
+ });
1450
+ }
1451
+ static parse(contents) {
1452
+ const rawComponent = JSON.parse(contents);
1453
+ return Component.from({
1454
+ name: rawComponent.box ? `${rawComponent.box}/${rawComponent.name}` : rawComponent.name,
1455
+ scope: rawComponent.scope,
1456
+ versions: (0, _lodash().mapValues)(rawComponent.versions, val => _objects().Ref.from(val)),
1457
+ lang: rawComponent.lang,
1458
+ deprecated: rawComponent.deprecated,
1459
+ bindingPrefix: rawComponent.bindingPrefix,
1460
+ state: rawComponent.state,
1461
+ orphanedVersions: (0, _lodash().mapValues)(rawComponent.orphanedVersions || {}, val => _objects().Ref.from(val)),
1462
+ scopesList: rawComponent.remotes,
1463
+ head: rawComponent.head ? _objects().Ref.from(rawComponent.head) : undefined,
1464
+ schema: rawComponent.schema || (rawComponent.head ? _legacy2().SchemaName.Harmony : _legacy2().SchemaName.Legacy),
1465
+ detachedHeads: _detachHeads().DetachedHeads.fromObject(rawComponent.detachedHeads)
1466
+ });
1467
+ }
1468
+ static from(props) {
1469
+ return new Component(props);
1470
+ }
1471
+ static fromBitId(bitId) {
1472
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
1473
+ return new Component({
1474
+ name: bitId.fullName,
1475
+ scope: bitId.scope
1476
+ });
1477
+ }
1478
+ get isLegacy() {
1479
+ return !this.schema || this.schema === _legacy2().SchemaName.Legacy;
1480
+ }
1481
+ validate() {
1482
+ const message = `unable to save Component object "${this.id()}"`;
1483
+ if (!this.name) throw new (_bitError().BitError)(`${message} the name is missing`);
1484
+ if (this.state && this.state.versions) {
1485
+ Object.keys(this.state.versions).forEach(version => {
1486
+ if ((0, _componentVersion().isTag)(version) && !this.hasTag(version)) {
1487
+ throw new (_legacyCli().ValidationError)(`${message}, the version ${version} is marked as staged but is not available`);
1488
+ }
1489
+ });
1490
+ }
1491
+ const hashDuplications = (0, _toolboxArray().findDuplications)(this.versionArray.map(v => v.toString()));
1492
+ if (hashDuplications.length) {
1493
+ throw new (_legacyCli().ValidationError)(`${message}, the following hash(es) are duplicated ${hashDuplications.join(', ')}`);
1494
+ }
1495
+ Object.keys(this.orphanedVersions).forEach(version => {
1496
+ if (this.versions[version]) {
1497
+ throw new (_legacyCli().ValidationError)(`${message}, the version "${version}" exists in orphanedVersions but it exits also in "versions" prop`);
1498
+ }
1499
+ });
1500
+ if (!this.isLegacy && !this.head && this.versionArray.length) {
1501
+ // legacy don't have head. also, when snapping on a lane the first time, there is no head.
1502
+ // tags are done on default lane only, so if there are versions (tag), it must have head
1503
+ throw new (_legacyCli().ValidationError)(`${message}, the "head" prop is missing`);
1504
+ }
1505
+ }
1506
+ }
1507
+ exports.default = Component;
1508
+
1509
+ //# sourceMappingURL=model-component.js.map