@teambit/objects 0.0.19

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 (123) hide show
  1. package/artifacts/__bit_junit.xml +68 -0
  2. package/artifacts/preview/teambit_scope_objects-preview.js +1 -0
  3. package/dist/fixtures/version-model-extended.json +48 -0
  4. package/dist/fixtures/version-model-object.json +87 -0
  5. package/dist/index.d.ts +19 -0
  6. package/dist/index.js +371 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/models/dependencies-graph.d.ts +45 -0
  9. package/dist/models/dependencies-graph.js +106 -0
  10. package/dist/models/dependencies-graph.js.map +1 -0
  11. package/dist/models/detach-heads.d.ts +25 -0
  12. package/dist/models/detach-heads.js +84 -0
  13. package/dist/models/detach-heads.js.map +1 -0
  14. package/dist/models/export-metadata.d.ts +24 -0
  15. package/dist/models/export-metadata.js +76 -0
  16. package/dist/models/export-metadata.js.map +1 -0
  17. package/dist/models/index.d.ts +10 -0
  18. package/dist/models/index.js +125 -0
  19. package/dist/models/index.js.map +1 -0
  20. package/dist/models/lane-history.d.ts +40 -0
  21. package/dist/models/lane-history.js +117 -0
  22. package/dist/models/lane-history.js.map +1 -0
  23. package/dist/models/lane.d.ts +124 -0
  24. package/dist/models/lane.js +463 -0
  25. package/dist/models/lane.js.map +1 -0
  26. package/dist/models/model-component.d.ts +317 -0
  27. package/dist/models/model-component.js +1365 -0
  28. package/dist/models/model-component.js.map +1 -0
  29. package/dist/models/model-component.spec.d.ts +1 -0
  30. package/dist/models/model-component.spec.js +71 -0
  31. package/dist/models/model-component.spec.js.map +1 -0
  32. package/dist/models/scopeMeta.d.ts +20 -0
  33. package/dist/models/scopeMeta.js +71 -0
  34. package/dist/models/scopeMeta.js.map +1 -0
  35. package/dist/models/source.d.ts +10 -0
  36. package/dist/models/source.js +43 -0
  37. package/dist/models/source.js.map +1 -0
  38. package/dist/models/symlink.d.ts +30 -0
  39. package/dist/models/symlink.js +91 -0
  40. package/dist/models/symlink.js.map +1 -0
  41. package/dist/models/version-history.d.ts +59 -0
  42. package/dist/models/version-history.js +285 -0
  43. package/dist/models/version-history.js.map +1 -0
  44. package/dist/models/version.d.ts +279 -0
  45. package/dist/models/version.js +777 -0
  46. package/dist/models/version.js.map +1 -0
  47. package/dist/models/version.spec.d.ts +1 -0
  48. package/dist/models/version.spec.js +340 -0
  49. package/dist/models/version.spec.js.map +1 -0
  50. package/dist/objects/bit-object-list.d.ts +24 -0
  51. package/dist/objects/bit-object-list.js +65 -0
  52. package/dist/objects/bit-object-list.js.map +1 -0
  53. package/dist/objects/index.d.ts +5 -0
  54. package/dist/objects/index.js +60 -0
  55. package/dist/objects/index.js.map +1 -0
  56. package/dist/objects/object-list-to-graph.d.ts +13 -0
  57. package/dist/objects/object-list-to-graph.js +93 -0
  58. package/dist/objects/object-list-to-graph.js.map +1 -0
  59. package/dist/objects/object-list.d.ts +52 -0
  60. package/dist/objects/object-list.js +369 -0
  61. package/dist/objects/object-list.js.map +1 -0
  62. package/dist/objects/object.d.ts +35 -0
  63. package/dist/objects/object.js +190 -0
  64. package/dist/objects/object.js.map +1 -0
  65. package/dist/objects/objects-readable-generator.d.ts +31 -0
  66. package/dist/objects/objects-readable-generator.js +192 -0
  67. package/dist/objects/objects-readable-generator.js.map +1 -0
  68. package/dist/objects/raw-object.d.ts +23 -0
  69. package/dist/objects/raw-object.js +155 -0
  70. package/dist/objects/raw-object.js.map +1 -0
  71. package/dist/objects/ref.d.ts +14 -0
  72. package/dist/objects/ref.js +45 -0
  73. package/dist/objects/ref.js.map +1 -0
  74. package/dist/objects/repository-hooks.d.ts +4 -0
  75. package/dist/objects/repository-hooks.js +56 -0
  76. package/dist/objects/repository-hooks.js.map +1 -0
  77. package/dist/objects/repository.d.ts +148 -0
  78. package/dist/objects/repository.js +842 -0
  79. package/dist/objects/repository.js.map +1 -0
  80. package/dist/objects/scope-index.d.ts +73 -0
  81. package/dist/objects/scope-index.js +251 -0
  82. package/dist/objects/scope-index.js.map +1 -0
  83. package/dist/objects/scope-index.spec.d.ts +1 -0
  84. package/dist/objects/scope-index.spec.js +152 -0
  85. package/dist/objects/scope-index.spec.js.map +1 -0
  86. package/dist/objects.aspect.d.ts +2 -0
  87. package/dist/objects.aspect.js +18 -0
  88. package/dist/objects.aspect.js.map +1 -0
  89. package/dist/objects.main.runtime.d.ts +7 -0
  90. package/dist/objects.main.runtime.js +36 -0
  91. package/dist/objects.main.runtime.js.map +1 -0
  92. package/dist/preview-1736824735631.js +7 -0
  93. package/fixtures/version-model-extended.json +48 -0
  94. package/fixtures/version-model-object.json +87 -0
  95. package/models/dependencies-graph.ts +119 -0
  96. package/models/detach-heads.ts +79 -0
  97. package/models/export-metadata.ts +57 -0
  98. package/models/index.ts +11 -0
  99. package/models/lane-history.ts +106 -0
  100. package/models/lane.ts +367 -0
  101. package/models/model-component.spec.ts +55 -0
  102. package/models/model-component.ts +1367 -0
  103. package/models/scopeMeta.ts +60 -0
  104. package/models/source.ts +32 -0
  105. package/models/symlink.ts +66 -0
  106. package/models/version-history.ts +266 -0
  107. package/models/version.spec.ts +288 -0
  108. package/models/version.ts +818 -0
  109. package/objects/bit-object-list.ts +59 -0
  110. package/objects/index.ts +6 -0
  111. package/objects/object-list-to-graph.ts +69 -0
  112. package/objects/object-list.ts +313 -0
  113. package/objects/object.ts +153 -0
  114. package/objects/objects-readable-generator.ts +167 -0
  115. package/objects/raw-object.ts +142 -0
  116. package/objects/ref.ts +45 -0
  117. package/objects/repository-hooks.ts +42 -0
  118. package/objects/repository.ts +753 -0
  119. package/objects/scope-index.spec.ts +95 -0
  120. package/objects/scope-index.ts +192 -0
  121. package/package.json +98 -0
  122. package/types/asset.d.ts +41 -0
  123. package/types/style.d.ts +42 -0
@@ -0,0 +1,818 @@
1
+ import { isEmpty, pickBy } from 'lodash';
2
+ import { isSnap } from '@teambit/component-version';
3
+ import { ComponentID, ComponentIdList } from '@teambit/component-id';
4
+ import { LaneId } from '@teambit/lane-id';
5
+ import { v4 } from 'uuid';
6
+ import { BuildStatus, DEFAULT_BUNDLE_FILENAME, Extensions } from '@teambit/legacy.constants';
7
+ import {
8
+ isSchemaSupport,
9
+ SchemaFeature,
10
+ SchemaName,
11
+ Dependencies,
12
+ Dependency,
13
+ ConsumerComponent,
14
+ } from '@teambit/legacy.consumer-component';
15
+ import { getRefsFromExtensions, SourceFile } from '@teambit/component.sources';
16
+ import { ComponentOverridesData } from '@teambit/legacy.consumer-config';
17
+ import { ExtensionDataEntry, ExtensionDataList } from '@teambit/legacy.extension-data';
18
+ import type { Doclet } from '@teambit/semantics.doc-parser';
19
+ import { logger } from '@teambit/legacy.logger';
20
+ import { getStringifyArgs, PathLinux, pathNormalizeToLinux } from '@teambit/legacy.utils';
21
+ import { sha1 } from '@teambit/toolbox.crypto.sha1';
22
+ import { BitObject, Ref, Repository } from '../objects';
23
+ import { ObjectItem } from '../objects/object-list';
24
+ import { BitIdCompIdError, VersionInvalid, validateVersionInstance } from '@teambit/legacy.scope';
25
+ import Source from './source';
26
+ import { DependenciesGraph } from './dependencies-graph';
27
+ import { getBitVersion } from '@teambit/bit.get-bit-version';
28
+
29
+ export type SourceFileModel = {
30
+ name: string;
31
+ relativePath: PathLinux;
32
+ test: boolean;
33
+ file: Ref;
34
+ };
35
+
36
+ export type DistFileModel = SourceFileModel;
37
+
38
+ export type ArtifactFileModel = {
39
+ relativePath: PathLinux;
40
+ file: Ref;
41
+ };
42
+
43
+ export type Log = {
44
+ message: string;
45
+ date: string;
46
+ username: string | undefined;
47
+ email: string | undefined;
48
+ };
49
+
50
+ export type DepEdgeType = 'prod' | 'dev' | 'peer' | 'ext';
51
+ export type DepEdge = { source: ComponentID; target: ComponentID; type: DepEdgeType };
52
+
53
+ type ExternalHead = { head: Ref; laneId: LaneId };
54
+ type SquashData = { previousParents: Ref[]; laneId: LaneId };
55
+ type VersionOrigin = { id: { scope: string; name: string }; lane?: { scope: string; name: string; hash: string } };
56
+
57
+ export type VersionProps = {
58
+ mainFile: PathLinux;
59
+ files: Array<SourceFileModel>;
60
+ log: Log;
61
+ docs?: Doclet[];
62
+ dependencies?: Dependency[];
63
+ devDependencies?: Dependency[];
64
+ peerDependencies?: Dependency[];
65
+ flattenedDependencies?: ComponentIdList;
66
+ _flattenedEdges?: DepEdge[];
67
+ flattenedEdges?: DepEdge[];
68
+ flattenedEdgesRef?: Ref;
69
+ dependenciesGraphRef?: Ref;
70
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
71
+ packageDependencies?: { [key: string]: string };
72
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
73
+ devPackageDependencies?: { [key: string]: string };
74
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
75
+ peerPackageDependencies?: { [key: string]: string };
76
+ bindingPrefix: string;
77
+ schema?: string;
78
+ overrides: ComponentOverridesData;
79
+ packageJsonChangedProps?: Record<string, any>;
80
+ hash?: string;
81
+ parents?: Ref[];
82
+ squashed?: SquashData;
83
+ unrelated?: ExternalHead;
84
+ extensions?: ExtensionDataList;
85
+ buildStatus?: BuildStatus;
86
+ componentId?: ComponentID;
87
+ bitVersion?: string;
88
+ modified?: Log[];
89
+ origin?: VersionOrigin;
90
+ hidden?: boolean;
91
+ };
92
+
93
+ /**
94
+ * Represent a version model in the scope
95
+ */
96
+ export default class Version extends BitObject {
97
+ mainFile: PathLinux;
98
+ files: Array<SourceFileModel>;
99
+ log: Log;
100
+ docs: Doclet[] | undefined;
101
+ dependencies: Dependencies;
102
+ devDependencies: Dependencies;
103
+ peerDependencies: Dependencies;
104
+ flattenedDependencies: ComponentIdList;
105
+ dependenciesGraphRef?: Ref;
106
+ _dependenciesGraph?: DependenciesGraph; // caching for the dependencies graph
107
+ flattenedEdgesRef?: Ref; // ref to a BitObject Source file, which is a JSON object containing the flattened edge
108
+ _flattenedEdges?: DepEdge[]; // caching for the flattenedEdges
109
+ /**
110
+ * @deprecated
111
+ * to get the flattenedEdges, please use `this.getFlattenedEdges()`.
112
+ * this function handles the backward compatibility and provides the flattened edges regardless whether it was saved
113
+ * the `flattenedEdgesRef` introduced or after.
114
+ *
115
+ * the reason this is left here is not for backward compatibility, but for forward compatibility. meaning, if a
116
+ * Version object created by the new version is parsed by an old version that doesn't support the flattenedEdgesRef,
117
+ * then, it'll be able to still get the flattenedEdges by this prop.
118
+ * this is causing duplication currently. the data is kept in both, `this.flattenedEdges` and the file stored in `flattenedEdgesRef`.
119
+ * so it'll be best to delete this prop as soon as all scopes are deployed with the new version.
120
+ * (around August 2023 should be safe)
121
+ */
122
+ private flattenedEdges: DepEdge[];
123
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
124
+ packageDependencies: { [key: string]: string };
125
+ devPackageDependencies: { [key: string]: string };
126
+ peerPackageDependencies: { [key: string]: string };
127
+ bindingPrefix: string;
128
+ schema: string | undefined;
129
+ overrides: ComponentOverridesData;
130
+ packageJsonChangedProps: Record<string, any>;
131
+ _hash: string; // reason for the underscore prefix is that we already have hash as a method
132
+ parents: Ref[];
133
+ squashed?: SquashData; // when a component is squashed during lane-merge
134
+ unrelated?: ExternalHead; // when a component from a lane was created with the same name/scope as main, this ref points to the component of the lane
135
+ extensions: ExtensionDataList;
136
+ buildStatus?: BuildStatus;
137
+ componentId?: ComponentID; // can help debugging errors when validating Version object
138
+ bitVersion?: string;
139
+ modified: Log[] = []; // currently mutation could happen as a result of either "squash" or "sign".
140
+ origin?: VersionOrigin; // for debugging purposes
141
+ hidden?: boolean; // whether the version is hidden from commands such as "bit log", "bit blame". (needed for un-meaningful snaps, such as merged-lane snap prior to the tag)
142
+
143
+ constructor(props: VersionProps) {
144
+ super();
145
+ this.mainFile = props.mainFile;
146
+ this.files = props.files;
147
+ this.log = props.log;
148
+ this.dependencies = new Dependencies(props.dependencies);
149
+ this.devDependencies = new Dependencies(props.devDependencies);
150
+ this.peerDependencies = new Dependencies(props.peerDependencies);
151
+ this.docs = props.docs;
152
+ this.flattenedDependencies = props.flattenedDependencies || new ComponentIdList();
153
+ this.flattenedEdges = props.flattenedEdges || [];
154
+ this.flattenedEdgesRef = props.flattenedEdgesRef;
155
+ this.dependenciesGraphRef = props.dependenciesGraphRef;
156
+ this.packageDependencies = props.packageDependencies || {};
157
+ this.devPackageDependencies = props.devPackageDependencies || {};
158
+ this.peerPackageDependencies = props.peerPackageDependencies || {};
159
+ this.bindingPrefix = props.bindingPrefix;
160
+ this.schema = props.schema;
161
+ this.overrides = props.overrides || {};
162
+ this.packageJsonChangedProps = props.packageJsonChangedProps || {};
163
+ // @ts-ignore yes, props.hash can be undefined here, but it gets populated as soon as Version is created
164
+ this._hash = props.hash;
165
+ this.parents = props.parents || [];
166
+ this.squashed = props.squashed;
167
+ this.unrelated = props.unrelated;
168
+ this.extensions = props.extensions || ExtensionDataList.fromArray([]);
169
+ this.buildStatus = props.buildStatus;
170
+ this.componentId = props.componentId;
171
+ this.bitVersion = props.bitVersion;
172
+ this.modified = props.modified || [];
173
+ this.origin = props.origin;
174
+ this.hidden = props.hidden;
175
+ this.validateVersion();
176
+ }
177
+
178
+ /**
179
+ * use only this method to get the flattened edges (graph of flattened dependencies).
180
+ * it's backward compatible with the previous way this was stored on the Version object itself.
181
+ */
182
+ async getFlattenedEdges(repo: Repository): Promise<DepEdge[]> {
183
+ const getWithBackwardCompatibility = async (): Promise<DepEdge[]> => {
184
+ if (this.flattenedEdgesRef) {
185
+ // it's possible that there is a ref but the file is not there.
186
+ // it can happen if the remote-scope uses an older version that doesn't know to collect this ref.
187
+ // in which case, the client will get the Version object with the ref prop, but not the Source object.
188
+ const throws = false;
189
+ const flattenedEdgesSource = (await repo.load(this.flattenedEdgesRef, throws)) as Source | undefined;
190
+ if (flattenedEdgesSource) {
191
+ const flattenedEdgesJson = JSON.parse(flattenedEdgesSource.contents.toString());
192
+ return flattenedEdgesJson.map((item) =>
193
+ Array.isArray(item) ? Version.depEdgeFromArray(item) : Version.depEdgeFromObject(item)
194
+ );
195
+ }
196
+ }
197
+ return this.flattenedEdges || [];
198
+ };
199
+
200
+ if (!this._flattenedEdges) {
201
+ this._flattenedEdges = await getWithBackwardCompatibility();
202
+ }
203
+
204
+ return this._flattenedEdges;
205
+ }
206
+
207
+ async loadDependenciesGraph(repo: Repository): Promise<DependenciesGraph | undefined> {
208
+ if (!this._dependenciesGraph) {
209
+ if (this.dependenciesGraphRef) {
210
+ // it's possible that there is a ref but the file is not there.
211
+ // it can happen if the remote-scope uses an older version that doesn't know to collect this ref.
212
+ // in which case, the client will get the Version object with the ref prop, but not the Source object.
213
+ const throws = false;
214
+ const dependenciesGraphSource = (await repo.load(this.dependenciesGraphRef, throws)) as Source | undefined;
215
+ if (dependenciesGraphSource) {
216
+ this._dependenciesGraph = DependenciesGraph.deserialize(dependenciesGraphSource.contents.toString());
217
+ }
218
+ }
219
+ }
220
+ return this._dependenciesGraph;
221
+ }
222
+
223
+ validateVersion() {
224
+ const nonEmptyFields = ['mainFile', 'files'];
225
+ nonEmptyFields.forEach((field) => {
226
+ if (!this[field]) {
227
+ throw new VersionInvalid(`failed creating a version object, the field "${field}" can't be empty`);
228
+ }
229
+ });
230
+ }
231
+
232
+ id() {
233
+ const obj = this.toObject();
234
+
235
+ // @todo: remove the entire dependencies.relativePaths from the ID (it's going to be a breaking change)
236
+ const getDependencies = (deps: Dependencies) => {
237
+ const clonedDependencies = deps.cloneAsString();
238
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
239
+ return clonedDependencies.map((dependency: Dependency) => {
240
+ return {
241
+ id: dependency.id,
242
+ relativePaths: dependency.relativePaths.map((relativePath) => {
243
+ return {
244
+ sourceRelativePath: relativePath.sourceRelativePath,
245
+ destinationRelativePath: relativePath.destinationRelativePath,
246
+ };
247
+ }),
248
+ };
249
+ });
250
+ };
251
+
252
+ const getExtensions = (extensions: ExtensionDataList) => {
253
+ const sortedConfigOnly = extensions.sortById().toConfigArray();
254
+ return sortedConfigOnly;
255
+ };
256
+
257
+ const filterFunction = (val, key) => {
258
+ if (
259
+ key === 'devDependencies' ||
260
+ key === 'extensionDependencies' ||
261
+ key === 'devPackageDependencies' ||
262
+ key === 'peerPackageDependencies' ||
263
+ key === 'overrides' ||
264
+ key === 'extensions'
265
+ ) {
266
+ return !isEmpty(val);
267
+ }
268
+ return !!val;
269
+ };
270
+
271
+ return JSON.stringify(
272
+ pickBy(
273
+ {
274
+ mainFile: obj.mainFile,
275
+ files: obj.files,
276
+ log: obj.log,
277
+ dependencies: getDependencies(this.dependencies),
278
+ devDependencies: getDependencies(this.devDependencies),
279
+ extensionDependencies: getDependencies(this.extensionDependencies),
280
+ packageDependencies: obj.packageDependencies,
281
+ devPackageDependencies: obj.devPackageDependencies,
282
+ peerPackageDependencies: obj.peerPackageDependencies,
283
+ bindingPrefix: obj.bindingPrefix,
284
+ overrides: obj.overrides,
285
+ extensions: getExtensions(this.extensions),
286
+ },
287
+ filterFunction
288
+ )
289
+ );
290
+ }
291
+
292
+ calculateHash(): Ref {
293
+ return new Ref(BitObject.makeHash(this.id()));
294
+ }
295
+
296
+ hash(): Ref {
297
+ if (!this._hash) {
298
+ throw new Error('hash is missing from a Version object');
299
+ }
300
+ return new Ref(this._hash);
301
+ }
302
+
303
+ get extensionDependencies() {
304
+ return new Dependencies(this.extensions.extensionsBitIds.map((id) => new Dependency(id, [])));
305
+ }
306
+
307
+ lastModified(): string {
308
+ if (!this.modified || !this.modified.length) return this.log.date;
309
+ return this.modified[this.modified.length - 1].date;
310
+ }
311
+
312
+ getAllFlattenedDependencies(): ComponentIdList {
313
+ return ComponentIdList.fromArray([...this.flattenedDependencies]);
314
+ }
315
+
316
+ getAllDependencies(): Dependency[] {
317
+ return [
318
+ ...this.dependencies.dependencies,
319
+ ...this.devDependencies.dependencies,
320
+ ...this.extensionDependencies.dependencies,
321
+ ];
322
+ }
323
+
324
+ get depsIdsGroupedByType(): {
325
+ dependencies: ComponentIdList;
326
+ devDependencies: ComponentIdList;
327
+ peerDependencies: ComponentIdList;
328
+ extensionDependencies: ComponentIdList;
329
+ } {
330
+ return {
331
+ dependencies: this.dependencies.getAllIds(),
332
+ devDependencies: this.devDependencies.getAllIds(),
333
+ peerDependencies: this.peerDependencies.getAllIds(),
334
+ extensionDependencies: this.extensions.extensionsBitIds,
335
+ };
336
+ }
337
+
338
+ getAllDependenciesCloned(): Dependencies {
339
+ const dependencies = [...this.dependencies.getClone(), ...this.devDependencies.getClone()];
340
+ return new Dependencies(dependencies);
341
+ }
342
+
343
+ getAllDependenciesIds(): ComponentIdList {
344
+ const allDependencies = Object.values(this.depsIdsGroupedByType).flat();
345
+ return ComponentIdList.fromArray(allDependencies);
346
+ }
347
+
348
+ getDependenciesIdsExcludeExtensions(): ComponentIdList {
349
+ return ComponentIdList.fromArray([...this.dependencies.getAllIds(), ...this.devDependencies.getAllIds()]);
350
+ }
351
+
352
+ updateFlattenedDependency(currentId: ComponentID, newId: ComponentID) {
353
+ const getUpdated = (flattenedDependencies: ComponentIdList): ComponentIdList => {
354
+ const updatedIds = flattenedDependencies.map((depId) => {
355
+ if (depId.isEqual(currentId)) return newId;
356
+ return depId;
357
+ });
358
+ return ComponentIdList.fromArray(updatedIds);
359
+ };
360
+ this.flattenedDependencies = getUpdated(this.flattenedDependencies);
361
+ }
362
+
363
+ refs(): Ref[] {
364
+ return this.refsWithOptions();
365
+ }
366
+
367
+ refsWithOptions(includeParents = true, includeArtifacts = true): Ref[] {
368
+ const allRefs: Ref[] = [];
369
+ const extractRefsFromFiles = (files) => {
370
+ const refs = files ? files.map((file) => file.file) : [];
371
+ return refs;
372
+ };
373
+ const files = extractRefsFromFiles(this.files);
374
+ allRefs.push(...files);
375
+ if (includeParents) {
376
+ allRefs.push(...this.parents);
377
+ }
378
+ if (includeArtifacts) {
379
+ const artifacts = getRefsFromExtensions(this.extensions);
380
+ allRefs.push(...artifacts);
381
+ }
382
+ if (this.flattenedEdgesRef) allRefs.push(this.flattenedEdgesRef);
383
+ if (this.dependenciesGraphRef) allRefs.push(this.dependenciesGraphRef);
384
+ return allRefs;
385
+ }
386
+
387
+ refsWithoutParents(): Ref[] {
388
+ const extractRefsFromFiles = (files) => {
389
+ const refs = files ? files.map((file) => file.file) : [];
390
+ return refs;
391
+ };
392
+ const files = extractRefsFromFiles(this.files);
393
+ const artifacts = getRefsFromExtensions(this.extensions);
394
+ return [...files, ...artifacts].filter((ref) => ref);
395
+ }
396
+
397
+ async collectManyObjects(repo: Repository, refs: Ref[]): Promise<ObjectItem[]> {
398
+ return repo.loadManyRaw(refs);
399
+ }
400
+
401
+ static depEdgeToObject(depEdge: DepEdge): Record<string, any> {
402
+ return {
403
+ source: depEdge.source.serialize(),
404
+ target: depEdge.target.serialize(),
405
+ type: depEdge.type,
406
+ };
407
+ }
408
+ static depEdgeFromObject(depEdgeObj: Record<string, any>): DepEdge {
409
+ return {
410
+ source: ComponentID.fromObject(depEdgeObj.source),
411
+ target: ComponentID.fromObject(depEdgeObj.target),
412
+ type: depEdgeObj.type,
413
+ };
414
+ }
415
+ static depEdgeToArray(depEdge: DepEdge): Record<string, any> {
416
+ return [depEdge.source.toString(), depEdge.target.toString(), depEdge.type];
417
+ }
418
+ static depEdgeFromArray(depEdgeArr: string[]): DepEdge {
419
+ const [sourceStr, targetStr, type] = depEdgeArr;
420
+ return {
421
+ source: ComponentID.fromString(sourceStr),
422
+ target: ComponentID.fromString(targetStr),
423
+ type: type as DepEdgeType,
424
+ };
425
+ }
426
+ static flattenedEdgeToSource(flattenedEdges?: DepEdge[]): Source | undefined {
427
+ if (!flattenedEdges) return undefined;
428
+ // @todo: around August 2024, uncomment this line and delete the next one.
429
+ // it'll make this object much much smaller (for 604 edges, it's now 143KB, with the array format it's 6KB!)
430
+ // const flattenedEdgesObj = flattenedEdges.map((f) => Version.depEdgeToArray(f));
431
+ const flattenedEdgesObj = flattenedEdges.map((f) => Version.depEdgeToObject(f));
432
+ const flattenedEdgesBuffer = Buffer.from(JSON.stringify(flattenedEdgesObj));
433
+ return Source.from(flattenedEdgesBuffer);
434
+ }
435
+ static dependenciesGraphToSource(dependenciesGraph?: DependenciesGraph): Source | undefined {
436
+ if (!dependenciesGraph) return undefined;
437
+ const dependenciesGraphBuffer = Buffer.from(dependenciesGraph.serialize());
438
+ return Source.from(dependenciesGraphBuffer);
439
+ }
440
+
441
+ toObject() {
442
+ const _convertFileToObject = (file) => {
443
+ return {
444
+ file: file.file.toString(),
445
+ relativePath: file.relativePath,
446
+ name: file.name,
447
+ test: file.test,
448
+ };
449
+ };
450
+
451
+ return pickBy(
452
+ {
453
+ files: this.files ? this.files.map(_convertFileToObject) : null,
454
+ mainFile: this.mainFile,
455
+ bindingPrefix: this.bindingPrefix,
456
+ schema: this.schema,
457
+ log: {
458
+ message: this.log.message,
459
+ date: this.log.date,
460
+ username: this.log.username,
461
+ email: this.log.email,
462
+ },
463
+ docs: this.docs,
464
+ dependencies: this.dependencies.cloneAsObject(),
465
+ devDependencies: this.devDependencies.cloneAsObject(),
466
+ flattenedDependencies: this.flattenedDependencies.map((dep) => dep.toObject()),
467
+ flattenedEdges: this.flattenedEdgesRef ? undefined : this.flattenedEdges.map((f) => Version.depEdgeToObject(f)),
468
+ flattenedEdgesRef: this.flattenedEdgesRef?.toString(),
469
+ dependenciesGraphRef: this.dependenciesGraphRef?.toString(),
470
+ extensions: this.extensions.toModelObjects(),
471
+ packageDependencies: this.packageDependencies,
472
+ devPackageDependencies: this.devPackageDependencies,
473
+ peerPackageDependencies: this.peerPackageDependencies,
474
+ overrides: this.overrides,
475
+ buildStatus: this.buildStatus,
476
+ packageJsonChangedProps: this.packageJsonChangedProps,
477
+ parents: this.parents.map((p) => p.toString()),
478
+ squashed: this.squashed
479
+ ? {
480
+ previousParents: this.squashed.previousParents.map((p) => p.toString()),
481
+ laneId: this.squashed.laneId.toObject(),
482
+ }
483
+ : undefined,
484
+ unrelated: this.unrelated
485
+ ? { head: this.unrelated.head.toString(), laneId: this.unrelated.laneId.toObject() }
486
+ : undefined,
487
+ bitVersion: this.bitVersion,
488
+ modified: this.modified,
489
+ origin: this.origin,
490
+ hidden: this.hidden,
491
+ },
492
+ (val) => !!val
493
+ );
494
+ }
495
+
496
+ validateBeforePersisting(versionStr: string): void {
497
+ logger.trace(`validating version object, hash: ${this.hash().hash}`);
498
+ const version = Version.parse(versionStr, this._hash);
499
+ version.validate();
500
+ }
501
+
502
+ toBuffer(pretty: boolean): Buffer {
503
+ const obj = this.toObject();
504
+ const args = getStringifyArgs(pretty);
505
+ const str = JSON.stringify(obj, ...args);
506
+ if (this.validateBeforePersist) this.validateBeforePersisting(str);
507
+ return Buffer.from(str);
508
+ }
509
+ /**
510
+ * used by the super class BitObject
511
+ */
512
+ static parse(contents: string, hash: string): Version {
513
+ const contentParsed = JSON.parse(contents);
514
+ const {
515
+ mainFile,
516
+ files,
517
+ bindingPrefix,
518
+ schema,
519
+ log,
520
+ docs,
521
+ dependencies,
522
+ devDependencies,
523
+ flattenedDependencies,
524
+ flattenedEdges,
525
+ flattenedEdgesRef,
526
+ dependenciesGraphRef,
527
+ flattenedDevDependencies,
528
+ devPackageDependencies,
529
+ peerPackageDependencies,
530
+ packageDependencies,
531
+ overrides,
532
+ packageJsonChangedProps,
533
+ extensions,
534
+ buildStatus,
535
+ parents,
536
+ squashed,
537
+ unrelated,
538
+ bitVersion,
539
+ modified,
540
+ origin,
541
+ hidden,
542
+ } = contentParsed;
543
+
544
+ const _getDependencies = (deps = []): Dependency[] => {
545
+ const getRelativePath = (relativePath) => {
546
+ if (relativePath.importSpecifiers) {
547
+ // backward compatibility. Before the massive validation was added, an item of
548
+ // relativePath.importSpecifiers array could be missing the mainFile property, which is
549
+ // an invalid ImportSpecifier. (instead the mainFile it had another importSpecifiers object).
550
+ relativePath.importSpecifiers = relativePath.importSpecifiers.filter(
551
+ (importSpecifier) => importSpecifier.mainFile
552
+ );
553
+ if (!relativePath.importSpecifiers.length) delete relativePath.importSpecifiers;
554
+ }
555
+
556
+ return relativePath;
557
+ };
558
+
559
+ return deps.map((dependency: any) => {
560
+ if (!dependency.id.scope) {
561
+ throw new BitIdCompIdError(dependency.id.name);
562
+ }
563
+ return new Dependency(
564
+ ComponentID.fromObject(dependency.id),
565
+ Array.isArray(dependency.relativePaths)
566
+ ? dependency.relativePaths.map(getRelativePath)
567
+ : dependency.relativePaths
568
+ );
569
+ });
570
+ };
571
+
572
+ const _getFlattenedDependencies = (deps = []): ComponentID[] => {
573
+ return deps.map((dep) => ComponentID.fromObject(dep));
574
+ };
575
+
576
+ const _groupFlattenedDependencies = () => {
577
+ // support backward compatibility. until v15, there was both flattenedDependencies and
578
+ // flattenedDevDependencies. since then, these both were grouped to one flattenedDependencies
579
+ const flattenedDeps = _getFlattenedDependencies(flattenedDependencies);
580
+ const flattenedDevDeps = _getFlattenedDependencies(flattenedDevDependencies);
581
+ return ComponentIdList.fromArray([...flattenedDeps, ...flattenedDevDeps]);
582
+ };
583
+
584
+ const parseFile = (file) => {
585
+ return {
586
+ file: Ref.from(file.file),
587
+ relativePath: file.relativePath,
588
+ name: file.name,
589
+ test: file.test,
590
+ };
591
+ };
592
+ const _getExtensions = (exts = []): ExtensionDataList => {
593
+ if (exts.length) {
594
+ const newExts = exts.map((extension: any) => {
595
+ if (extension.extensionId) {
596
+ const extensionId = ComponentID.fromObject(extension.extensionId);
597
+ const entry = new ExtensionDataEntry(undefined, extensionId, undefined, extension.config, extension.data);
598
+ return entry;
599
+ }
600
+ const entry = new ExtensionDataEntry(
601
+ extension.id,
602
+ undefined,
603
+ extension.name,
604
+ extension.config,
605
+ extension.data
606
+ );
607
+ return entry;
608
+ });
609
+ return ExtensionDataList.fromModelObject(newExts);
610
+ }
611
+ return new ExtensionDataList();
612
+ };
613
+
614
+ return new Version({
615
+ mainFile,
616
+ files: files.map(parseFile),
617
+ bindingPrefix,
618
+ schema: schema || undefined,
619
+ log: {
620
+ // workaround for a bug where the log.message was saved as boolean when running `bit tag -m ""`
621
+ // the bug was fixed since v0.1.27, but old objects might still have this bug
622
+ message: typeof log.message !== 'string' ? '' : log.message,
623
+ date: log.date,
624
+ username: log.username,
625
+ email: log.email,
626
+ },
627
+ docs,
628
+ dependencies: _getDependencies(dependencies),
629
+ devDependencies: _getDependencies(devDependencies),
630
+ flattenedDependencies: _groupFlattenedDependencies(),
631
+ // backward compatibility. before introducing `flattenedEdgesRef`, we only had `flattenedEdges`. see getFlattenedEdges() for more info.
632
+ flattenedEdges: flattenedEdgesRef ? [] : flattenedEdges?.map((f) => Version.depEdgeFromObject(f)) || [],
633
+ flattenedEdgesRef: flattenedEdgesRef ? Ref.from(flattenedEdgesRef) : undefined,
634
+ dependenciesGraphRef: dependenciesGraphRef ? Ref.from(dependenciesGraphRef) : undefined,
635
+ devPackageDependencies,
636
+ peerPackageDependencies,
637
+ packageDependencies,
638
+ overrides,
639
+ packageJsonChangedProps,
640
+ hash,
641
+ parents: parents ? parents.map((p) => Ref.from(p)) : [],
642
+ squashed: squashed
643
+ ? { previousParents: squashed.previousParents.map((r) => Ref.from(r)), laneId: new LaneId(squashed.laneId) }
644
+ : undefined,
645
+ unrelated: unrelated ? { head: Ref.from(unrelated.head), laneId: new LaneId(unrelated.laneId) } : undefined,
646
+ extensions: _getExtensions(extensions),
647
+ buildStatus,
648
+ bitVersion,
649
+ modified,
650
+ origin,
651
+ hidden,
652
+ });
653
+ }
654
+
655
+ /**
656
+ * used by raw-object.toRealObject()
657
+ */
658
+ static from(versionProps: VersionProps, hash: string): Version {
659
+ return Version.parse(JSON.stringify(versionProps), hash);
660
+ }
661
+
662
+ /**
663
+ * Create version model object from consumer component
664
+ * @param {*} param0
665
+ */
666
+ static fromComponent({
667
+ component,
668
+ files,
669
+ flattenedEdges,
670
+ dependenciesGraph,
671
+ }: {
672
+ component: ConsumerComponent;
673
+ files: Array<SourceFileModel>;
674
+ flattenedEdges?: Source;
675
+ dependenciesGraph?: Source;
676
+ }) {
677
+ const parseFile = (file) => {
678
+ return {
679
+ file: file.file.hash(),
680
+ relativePath: file.relativePath,
681
+ name: file.name,
682
+ test: file.test,
683
+ };
684
+ };
685
+
686
+ if (!component.log) throw new Error('Version.fromComponent - component.log is missing');
687
+ const version = new Version({
688
+ mainFile: pathNormalizeToLinux(component.mainFile),
689
+ files: files.map(parseFile),
690
+ bindingPrefix: component.bindingPrefix,
691
+ log: component.log as Log,
692
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
693
+ docs: component.docs,
694
+ dependencies: component.dependencies.get(),
695
+ devDependencies: component.devDependencies.get(),
696
+ packageDependencies: component.packageDependencies,
697
+ devPackageDependencies: component.devPackageDependencies,
698
+ peerPackageDependencies: component.peerPackageDependencies,
699
+ dependenciesGraphRef: dependenciesGraph?.hash(),
700
+ flattenedDependencies: component.flattenedDependencies,
701
+ // it's safe to remove this line once the version.flattenedEdges prop is deleted
702
+ flattenedEdges: component.flattenedEdges,
703
+ flattenedEdgesRef: flattenedEdges?.hash(),
704
+ schema: component.schema,
705
+ overrides: component.overrides.componentOverridesData,
706
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
707
+ packageJsonChangedProps: component.packageJsonChangedProps,
708
+ extensions: component.extensions,
709
+ buildStatus: component.buildStatus,
710
+ componentId: component.id,
711
+ bitVersion: getBitVersion(),
712
+ });
713
+ if (isSnap(component.version)) {
714
+ version._hash = component.version as string;
715
+ } else {
716
+ version.setNewHash();
717
+ }
718
+
719
+ return version;
720
+ }
721
+
722
+ setNewHash() {
723
+ this._hash = sha1(v4());
724
+ }
725
+
726
+ get ignoreSharedDir(): boolean {
727
+ return !isSchemaSupport(SchemaFeature.sharedDir, this.schema);
728
+ }
729
+
730
+ get isLegacy(): boolean {
731
+ return !this.schema || this.schema === SchemaName.Legacy;
732
+ }
733
+
734
+ get originLaneId(): LaneId | undefined {
735
+ return this.origin?.lane ? new LaneId({ name: this.origin.lane.name, scope: this.origin.lane.scope }) : undefined;
736
+ }
737
+ get originId(): ComponentID | undefined {
738
+ return this.origin?.id
739
+ ? ComponentID.fromObject({ scope: this.origin.id.scope, name: this.origin.id.name })
740
+ : undefined;
741
+ }
742
+
743
+ setDist(dist: Source | undefined) {
744
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
745
+ this.dist = dist
746
+ ? {
747
+ file: dist.hash(),
748
+ name: DEFAULT_BUNDLE_FILENAME,
749
+ }
750
+ : null;
751
+ }
752
+
753
+ hasParent(ref: Ref) {
754
+ return this.parents.find((p) => p.toString() === ref.toString());
755
+ }
756
+
757
+ addParent(ref: Ref) {
758
+ if (this.isLegacy) return;
759
+ if (this.hasParent(ref)) {
760
+ return; // make sure to not add twice
761
+ }
762
+ this.parents.push(ref);
763
+ }
764
+
765
+ setSquashed(squashData: SquashData, log: Log, replaceMessage?: string) {
766
+ this.squashed = squashData;
767
+ this.addModifiedLog(log);
768
+ if (replaceMessage) {
769
+ this.addModifiedLog({
770
+ username: undefined,
771
+ email: undefined,
772
+ date: Date.now().toString(),
773
+ message: `squashing: replacing the original log.message, which was: "${this.log.message || '<empty>'}"`,
774
+ });
775
+ this.log.message = replaceMessage;
776
+ }
777
+ }
778
+
779
+ setUnrelated(externalHead: ExternalHead) {
780
+ this.unrelated = externalHead;
781
+ }
782
+
783
+ addModifiedLog(log: Log) {
784
+ this.modified.push(log);
785
+ }
786
+
787
+ addAsOnlyParent(ref: Ref) {
788
+ if (this.isLegacy) return;
789
+ this.parents = [ref];
790
+ }
791
+
792
+ removeParent(ref: Ref) {
793
+ this.parents = this.parents.filter((p) => p.toString() !== ref.toString());
794
+ }
795
+
796
+ removeAllParents() {
797
+ this.parents = [];
798
+ }
799
+
800
+ modelFilesToSourceFiles(repository: Repository): Promise<SourceFile[]> {
801
+ return Promise.all(this.files.map((file) => SourceFile.loadFromSourceFileModel(file, repository)));
802
+ }
803
+
804
+ isRemoved(): boolean {
805
+ return Boolean(this.extensions.findCoreExtension(Extensions.remove)?.config?.removed);
806
+ }
807
+ shouldRemoveFromMain(): boolean {
808
+ return Boolean(this.extensions.findCoreExtension(Extensions.remove)?.config?.removeOnMain);
809
+ }
810
+
811
+ /**
812
+ * Validate the version model properties, to make sure we are not inserting something
813
+ * in the wrong format
814
+ */
815
+ validate(): void {
816
+ validateVersionInstance(this);
817
+ }
818
+ }