@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.
- package/artifacts/__bit_junit.xml +68 -0
- package/artifacts/preview/teambit_scope_objects-preview.js +1 -0
- package/dist/fixtures/version-model-extended.json +48 -0
- package/dist/fixtures/version-model-object.json +87 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/models/dependencies-graph.d.ts +45 -0
- package/dist/models/dependencies-graph.js +106 -0
- package/dist/models/dependencies-graph.js.map +1 -0
- package/dist/models/detach-heads.d.ts +25 -0
- package/dist/models/detach-heads.js +84 -0
- package/dist/models/detach-heads.js.map +1 -0
- package/dist/models/export-metadata.d.ts +24 -0
- package/dist/models/export-metadata.js +76 -0
- package/dist/models/export-metadata.js.map +1 -0
- package/dist/models/index.d.ts +10 -0
- package/dist/models/index.js +125 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/lane-history.d.ts +40 -0
- package/dist/models/lane-history.js +117 -0
- package/dist/models/lane-history.js.map +1 -0
- package/dist/models/lane.d.ts +124 -0
- package/dist/models/lane.js +463 -0
- package/dist/models/lane.js.map +1 -0
- package/dist/models/model-component.d.ts +317 -0
- package/dist/models/model-component.js +1365 -0
- package/dist/models/model-component.js.map +1 -0
- package/dist/models/model-component.spec.d.ts +1 -0
- package/dist/models/model-component.spec.js +71 -0
- package/dist/models/model-component.spec.js.map +1 -0
- package/dist/models/scopeMeta.d.ts +20 -0
- package/dist/models/scopeMeta.js +71 -0
- package/dist/models/scopeMeta.js.map +1 -0
- package/dist/models/source.d.ts +10 -0
- package/dist/models/source.js +43 -0
- package/dist/models/source.js.map +1 -0
- package/dist/models/symlink.d.ts +30 -0
- package/dist/models/symlink.js +91 -0
- package/dist/models/symlink.js.map +1 -0
- package/dist/models/version-history.d.ts +59 -0
- package/dist/models/version-history.js +285 -0
- package/dist/models/version-history.js.map +1 -0
- package/dist/models/version.d.ts +279 -0
- package/dist/models/version.js +777 -0
- package/dist/models/version.js.map +1 -0
- package/dist/models/version.spec.d.ts +1 -0
- package/dist/models/version.spec.js +340 -0
- package/dist/models/version.spec.js.map +1 -0
- package/dist/objects/bit-object-list.d.ts +24 -0
- package/dist/objects/bit-object-list.js +65 -0
- package/dist/objects/bit-object-list.js.map +1 -0
- package/dist/objects/index.d.ts +5 -0
- package/dist/objects/index.js +60 -0
- package/dist/objects/index.js.map +1 -0
- package/dist/objects/object-list-to-graph.d.ts +13 -0
- package/dist/objects/object-list-to-graph.js +93 -0
- package/dist/objects/object-list-to-graph.js.map +1 -0
- package/dist/objects/object-list.d.ts +52 -0
- package/dist/objects/object-list.js +369 -0
- package/dist/objects/object-list.js.map +1 -0
- package/dist/objects/object.d.ts +35 -0
- package/dist/objects/object.js +190 -0
- package/dist/objects/object.js.map +1 -0
- package/dist/objects/objects-readable-generator.d.ts +31 -0
- package/dist/objects/objects-readable-generator.js +192 -0
- package/dist/objects/objects-readable-generator.js.map +1 -0
- package/dist/objects/raw-object.d.ts +23 -0
- package/dist/objects/raw-object.js +155 -0
- package/dist/objects/raw-object.js.map +1 -0
- package/dist/objects/ref.d.ts +14 -0
- package/dist/objects/ref.js +45 -0
- package/dist/objects/ref.js.map +1 -0
- package/dist/objects/repository-hooks.d.ts +4 -0
- package/dist/objects/repository-hooks.js +56 -0
- package/dist/objects/repository-hooks.js.map +1 -0
- package/dist/objects/repository.d.ts +148 -0
- package/dist/objects/repository.js +842 -0
- package/dist/objects/repository.js.map +1 -0
- package/dist/objects/scope-index.d.ts +73 -0
- package/dist/objects/scope-index.js +251 -0
- package/dist/objects/scope-index.js.map +1 -0
- package/dist/objects/scope-index.spec.d.ts +1 -0
- package/dist/objects/scope-index.spec.js +152 -0
- package/dist/objects/scope-index.spec.js.map +1 -0
- package/dist/objects.aspect.d.ts +2 -0
- package/dist/objects.aspect.js +18 -0
- package/dist/objects.aspect.js.map +1 -0
- package/dist/objects.main.runtime.d.ts +7 -0
- package/dist/objects.main.runtime.js +36 -0
- package/dist/objects.main.runtime.js.map +1 -0
- package/dist/preview-1736824735631.js +7 -0
- package/fixtures/version-model-extended.json +48 -0
- package/fixtures/version-model-object.json +87 -0
- package/models/dependencies-graph.ts +119 -0
- package/models/detach-heads.ts +79 -0
- package/models/export-metadata.ts +57 -0
- package/models/index.ts +11 -0
- package/models/lane-history.ts +106 -0
- package/models/lane.ts +367 -0
- package/models/model-component.spec.ts +55 -0
- package/models/model-component.ts +1367 -0
- package/models/scopeMeta.ts +60 -0
- package/models/source.ts +32 -0
- package/models/symlink.ts +66 -0
- package/models/version-history.ts +266 -0
- package/models/version.spec.ts +288 -0
- package/models/version.ts +818 -0
- package/objects/bit-object-list.ts +59 -0
- package/objects/index.ts +6 -0
- package/objects/object-list-to-graph.ts +69 -0
- package/objects/object-list.ts +313 -0
- package/objects/object.ts +153 -0
- package/objects/objects-readable-generator.ts +167 -0
- package/objects/raw-object.ts +142 -0
- package/objects/ref.ts +45 -0
- package/objects/repository-hooks.ts +42 -0
- package/objects/repository.ts +753 -0
- package/objects/scope-index.spec.ts +95 -0
- package/objects/scope-index.ts +192 -0
- package/package.json +98 -0
- package/types/asset.d.ts +41 -0
- package/types/style.d.ts +42 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
import { v4 } from 'uuid';
|
2
|
+
import { getStringifyArgs } from '@teambit/legacy.utils';
|
3
|
+
import { getBasicLog } from '@teambit/harmony.modules.get-basic-log';
|
4
|
+
import { BitObject } from '../objects';
|
5
|
+
import Lane from './lane';
|
6
|
+
|
7
|
+
type Log = { date: string; username?: string; email?: string; message?: string };
|
8
|
+
|
9
|
+
export type HistoryItem = {
|
10
|
+
log: Log;
|
11
|
+
components: string[];
|
12
|
+
deleted?: string[];
|
13
|
+
};
|
14
|
+
|
15
|
+
type History = { [uuid: string]: HistoryItem };
|
16
|
+
|
17
|
+
type LaneHistoryProps = {
|
18
|
+
name: string;
|
19
|
+
scope: string;
|
20
|
+
laneHash: string;
|
21
|
+
history: History;
|
22
|
+
};
|
23
|
+
|
24
|
+
export class LaneHistory extends BitObject {
|
25
|
+
private name: string;
|
26
|
+
private scope: string;
|
27
|
+
private laneHash: string;
|
28
|
+
private history: History;
|
29
|
+
|
30
|
+
constructor(props: LaneHistoryProps) {
|
31
|
+
super();
|
32
|
+
this.name = props.name;
|
33
|
+
this.scope = props.scope;
|
34
|
+
this.laneHash = props.laneHash;
|
35
|
+
this.history = props.history;
|
36
|
+
}
|
37
|
+
|
38
|
+
id() {
|
39
|
+
return `${this.laneHash}:${LaneHistory.name}`;
|
40
|
+
}
|
41
|
+
|
42
|
+
static fromLaneObject(laneObject: Lane): LaneHistory {
|
43
|
+
return new LaneHistory({
|
44
|
+
scope: laneObject.scope,
|
45
|
+
name: laneObject.name,
|
46
|
+
laneHash: laneObject.hash().toString(),
|
47
|
+
history: {},
|
48
|
+
});
|
49
|
+
}
|
50
|
+
|
51
|
+
toObject(): Record<string, any> {
|
52
|
+
return {
|
53
|
+
name: this.name,
|
54
|
+
scope: this.scope,
|
55
|
+
laneHash: this.laneHash,
|
56
|
+
history: this.history,
|
57
|
+
};
|
58
|
+
}
|
59
|
+
|
60
|
+
toString(pretty: boolean): string {
|
61
|
+
const args = getStringifyArgs(pretty);
|
62
|
+
return JSON.stringify(this.toObject(), ...args);
|
63
|
+
}
|
64
|
+
|
65
|
+
toBuffer(pretty): Buffer {
|
66
|
+
return Buffer.from(this.toString(pretty));
|
67
|
+
}
|
68
|
+
|
69
|
+
getHistory(): History {
|
70
|
+
return this.history;
|
71
|
+
}
|
72
|
+
|
73
|
+
async addHistory(laneObj: Lane, msg?: string) {
|
74
|
+
const log: Log = await getBasicLog();
|
75
|
+
if (msg) log.message = msg;
|
76
|
+
const components = laneObj.toComponentIds().toStringArray();
|
77
|
+
const deleted = laneObj.components
|
78
|
+
.filter((c) => c.isDeleted)
|
79
|
+
.map((c) => c.id.changeVersion(c.head.toString()).toString());
|
80
|
+
this.history[v4()] = { log, components, ...(deleted.length && { deleted }) };
|
81
|
+
}
|
82
|
+
|
83
|
+
merge(laneHistory: LaneHistory) {
|
84
|
+
this.history = { ...this.history, ...laneHistory.history };
|
85
|
+
}
|
86
|
+
|
87
|
+
static create(name: string, scope: string, laneHash: string) {
|
88
|
+
return new LaneHistory({
|
89
|
+
name,
|
90
|
+
scope,
|
91
|
+
laneHash,
|
92
|
+
history: {},
|
93
|
+
});
|
94
|
+
}
|
95
|
+
|
96
|
+
static parse(contents: string): LaneHistory {
|
97
|
+
const parsed = JSON.parse(contents);
|
98
|
+
const props: LaneHistoryProps = {
|
99
|
+
name: parsed.name,
|
100
|
+
scope: parsed.scope,
|
101
|
+
laneHash: parsed.laneHash,
|
102
|
+
history: parsed.history,
|
103
|
+
};
|
104
|
+
return new LaneHistory(props);
|
105
|
+
}
|
106
|
+
}
|
package/models/lane.ts
ADDED
@@ -0,0 +1,367 @@
|
|
1
|
+
import { v4 } from 'uuid';
|
2
|
+
import { gte } from 'semver';
|
3
|
+
import { cloneDeep, isEqual, pickBy } from 'lodash';
|
4
|
+
import { BitError } from '@teambit/bit-error';
|
5
|
+
import { ComponentID, ComponentIdList } from '@teambit/component-id';
|
6
|
+
import { isSnap } from '@teambit/component-version';
|
7
|
+
import { LaneId, DEFAULT_LANE, LANE_REMOTE_DELIMITER } from '@teambit/lane-id';
|
8
|
+
import { Scope } from '@teambit/legacy.scope';
|
9
|
+
import { CFG_USER_EMAIL_KEY, CFG_USER_NAME_KEY, PREVIOUS_DEFAULT_LANE } from '@teambit/legacy.constants';
|
10
|
+
import { ValidationError } from '@teambit/legacy.cli.error';
|
11
|
+
import { logger } from '@teambit/legacy.logger';
|
12
|
+
import { getStringifyArgs } from '@teambit/legacy.utils';
|
13
|
+
import { sha1 } from '@teambit/toolbox.crypto.sha1';
|
14
|
+
import { hasVersionByRef } from '@teambit/component.snap-distance';
|
15
|
+
import { BitObject, Ref, Repository } from '../objects';
|
16
|
+
import Version from './version';
|
17
|
+
import * as globalConfig from '@teambit/legacy.global-config';
|
18
|
+
|
19
|
+
export type Log = { date: string; username?: string; email?: string; profileImage?: string };
|
20
|
+
|
21
|
+
export type LaneProps = {
|
22
|
+
name: string;
|
23
|
+
scope: string;
|
24
|
+
log: Log;
|
25
|
+
components?: LaneComponent[];
|
26
|
+
hash: string;
|
27
|
+
schema?: string;
|
28
|
+
readmeComponent?: LaneReadmeComponent;
|
29
|
+
forkedFrom?: LaneId;
|
30
|
+
updateDependents?: ComponentID[];
|
31
|
+
overrideUpdateDependents?: boolean;
|
32
|
+
};
|
33
|
+
|
34
|
+
const OLD_LANE_SCHEMA = '0.0.0';
|
35
|
+
const SCHEMA_INCLUDING_DELETED_COMPONENTS_DATA = '1.0.0';
|
36
|
+
const CURRENT_LANE_SCHEMA = SCHEMA_INCLUDING_DELETED_COMPONENTS_DATA;
|
37
|
+
|
38
|
+
export type LaneComponent = { id: ComponentID; head: Ref; isDeleted?: boolean };
|
39
|
+
export type LaneReadmeComponent = { id: ComponentID; head: Ref | null };
|
40
|
+
export default class Lane extends BitObject {
|
41
|
+
name: string;
|
42
|
+
scope: string;
|
43
|
+
components: LaneComponent[];
|
44
|
+
log: Log;
|
45
|
+
schema: string;
|
46
|
+
readmeComponent?: LaneReadmeComponent;
|
47
|
+
forkedFrom?: LaneId;
|
48
|
+
_hash: string; // reason for the underscore prefix is that we already have hash as a method
|
49
|
+
isNew = false; // doesn't get saved in the object. only needed for in-memory instance
|
50
|
+
hasChanged = false; // doesn't get saved in the object. only needed for in-memory instance
|
51
|
+
/**
|
52
|
+
* populated when a user clicks on "update" in the UI. it's a list of components that are dependents on the
|
53
|
+
* components in the lane. their dependencies are updated according to the lane.
|
54
|
+
* from the CLI perspective, it's added by "bit _snap" and merged by "bit _merge-lane".
|
55
|
+
* otherwise, the user is not aware of it. it's not imported to the workspace and the objects are not fetched.
|
56
|
+
*/
|
57
|
+
updateDependents?: ComponentID[];
|
58
|
+
private overrideUpdateDependents?: boolean;
|
59
|
+
constructor(props: LaneProps) {
|
60
|
+
super();
|
61
|
+
if (!props.name) throw new TypeError('Lane constructor expects to get a name parameter');
|
62
|
+
this.name = props.name;
|
63
|
+
this.scope = props.scope;
|
64
|
+
this.components = props.components || [];
|
65
|
+
this.log = props.log || { date: Date.now().toString() };
|
66
|
+
this._hash = props.hash;
|
67
|
+
this.readmeComponent = props.readmeComponent;
|
68
|
+
this.forkedFrom = props.forkedFrom;
|
69
|
+
this.schema = props.schema || OLD_LANE_SCHEMA;
|
70
|
+
this.updateDependents = props.updateDependents;
|
71
|
+
this.overrideUpdateDependents = props.overrideUpdateDependents;
|
72
|
+
}
|
73
|
+
id(): string {
|
74
|
+
return this.scope + LANE_REMOTE_DELIMITER + this.name;
|
75
|
+
}
|
76
|
+
hash(): Ref {
|
77
|
+
if (!this._hash) {
|
78
|
+
throw new Error('hash is missing from a Lane object');
|
79
|
+
}
|
80
|
+
return new Ref(this._hash);
|
81
|
+
}
|
82
|
+
changeName(name: string) {
|
83
|
+
this.name = name;
|
84
|
+
this.hasChanged = true;
|
85
|
+
}
|
86
|
+
changeScope(scope: string) {
|
87
|
+
this.scope = scope;
|
88
|
+
this.hasChanged = true;
|
89
|
+
}
|
90
|
+
refs(): Ref[] {
|
91
|
+
return this.components.map((c) => c.head);
|
92
|
+
}
|
93
|
+
validateBeforePersisting(str: string) {
|
94
|
+
logger.debug(`validating lane object: ${this.hash().toString()} ${this.id()}`);
|
95
|
+
const lane = Lane.parse(str, this.hash().toString());
|
96
|
+
lane.validate();
|
97
|
+
}
|
98
|
+
toObject() {
|
99
|
+
const obj = pickBy(
|
100
|
+
{
|
101
|
+
name: this.name,
|
102
|
+
scope: this.scope,
|
103
|
+
components: this.components.map((component) => ({
|
104
|
+
id: { scope: component.id.scope, name: component.id.fullName },
|
105
|
+
head: component.head.toString(),
|
106
|
+
...(component.isDeleted && { isDeleted: component.isDeleted }),
|
107
|
+
})),
|
108
|
+
log: this.log,
|
109
|
+
readmeComponent: this.readmeComponent && {
|
110
|
+
id: { scope: this.readmeComponent.id.scope, name: this.readmeComponent.id.fullName },
|
111
|
+
head: this.readmeComponent.head?.toString() ?? null,
|
112
|
+
},
|
113
|
+
forkedFrom: this.forkedFrom && this.forkedFrom.toObject(),
|
114
|
+
schema: this.schema,
|
115
|
+
updateDependents: this.updateDependents?.map((c) => c.toString()),
|
116
|
+
overrideUpdateDependents: this.overrideUpdateDependents,
|
117
|
+
},
|
118
|
+
(val) => !!val
|
119
|
+
);
|
120
|
+
return obj;
|
121
|
+
}
|
122
|
+
static from(props: LaneProps): Lane {
|
123
|
+
return new Lane(props);
|
124
|
+
}
|
125
|
+
static create(
|
126
|
+
name: string,
|
127
|
+
scope: string,
|
128
|
+
forkedFrom?: LaneId,
|
129
|
+
bitCloudUser?: {
|
130
|
+
username?: string;
|
131
|
+
email?: string;
|
132
|
+
profileImage?: string;
|
133
|
+
}
|
134
|
+
) {
|
135
|
+
const log = {
|
136
|
+
date: Date.now().toString(),
|
137
|
+
username: bitCloudUser?.username || globalConfig.getSync(CFG_USER_NAME_KEY),
|
138
|
+
email: bitCloudUser?.email || globalConfig.getSync(CFG_USER_EMAIL_KEY),
|
139
|
+
profileImage: bitCloudUser?.profileImage,
|
140
|
+
};
|
141
|
+
const lane = new Lane({ name, scope, hash: sha1(v4()), log, forkedFrom, schema: CURRENT_LANE_SCHEMA });
|
142
|
+
lane.isNew = true;
|
143
|
+
lane.hasChanged = true;
|
144
|
+
return lane;
|
145
|
+
}
|
146
|
+
static parse(contents: string, hash: string): Lane {
|
147
|
+
const laneObject = JSON.parse(contents);
|
148
|
+
return Lane.from({
|
149
|
+
name: laneObject.name,
|
150
|
+
scope: laneObject.scope,
|
151
|
+
log: laneObject.log,
|
152
|
+
components: laneObject.components.map((component) => ({
|
153
|
+
id: ComponentID.fromObject({ scope: component.id.scope, name: component.id.name }),
|
154
|
+
head: new Ref(component.head),
|
155
|
+
isDeleted: component.isDeleted,
|
156
|
+
})),
|
157
|
+
readmeComponent: laneObject.readmeComponent && {
|
158
|
+
id: ComponentID.fromObject({
|
159
|
+
scope: laneObject.readmeComponent.id.scope,
|
160
|
+
name: laneObject.readmeComponent.id.name,
|
161
|
+
}),
|
162
|
+
head: laneObject.readmeComponent.head && new Ref(laneObject.readmeComponent.head),
|
163
|
+
},
|
164
|
+
forkedFrom: laneObject.forkedFrom && LaneId.from(laneObject.forkedFrom.name, laneObject.forkedFrom.scope),
|
165
|
+
updateDependents: laneObject.updateDependents?.map((c) => ComponentID.fromString(c)),
|
166
|
+
overrideUpdateDependents: laneObject.overrideUpdateDependents,
|
167
|
+
hash: laneObject.hash || hash,
|
168
|
+
schema: laneObject.schema,
|
169
|
+
});
|
170
|
+
}
|
171
|
+
toBuffer(pretty?: boolean) {
|
172
|
+
const args = getStringifyArgs(pretty);
|
173
|
+
const obj = this.toObject();
|
174
|
+
const str = JSON.stringify(obj, ...args);
|
175
|
+
if (this.validateBeforePersist) this.validateBeforePersisting(str);
|
176
|
+
return Buffer.from(str);
|
177
|
+
}
|
178
|
+
addComponent(component: LaneComponent) {
|
179
|
+
const existsComponent = this.getComponent(component.id);
|
180
|
+
if (existsComponent) {
|
181
|
+
if (!existsComponent.head.isEqual(component.head)) this.hasChanged = true;
|
182
|
+
existsComponent.id = component.id;
|
183
|
+
existsComponent.head = component.head;
|
184
|
+
existsComponent.isDeleted = component.isDeleted;
|
185
|
+
} else {
|
186
|
+
logger.debug(`Lane.addComponent, adding component ${component.id.toString()} to lane ${this.id()}`);
|
187
|
+
this.components.push(component);
|
188
|
+
this.hasChanged = true;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
removeComponentFromUpdateDependentsIfExist(componentId: ComponentID) {
|
192
|
+
const updateDependentsList = ComponentIdList.fromArray(this.updateDependents || []);
|
193
|
+
const exist = updateDependentsList.searchWithoutVersion(componentId);
|
194
|
+
if (!exist) return;
|
195
|
+
this.updateDependents = updateDependentsList.removeIfExist(exist);
|
196
|
+
if (!this.updateDependents.length) this.updateDependents = undefined;
|
197
|
+
this.hasChanged = true;
|
198
|
+
}
|
199
|
+
addComponentToUpdateDependents(componentId: ComponentID) {
|
200
|
+
this.removeComponentFromUpdateDependentsIfExist(componentId);
|
201
|
+
(this.updateDependents ||= []).push(componentId);
|
202
|
+
this.hasChanged = true;
|
203
|
+
}
|
204
|
+
removeAllUpdateDependents() {
|
205
|
+
if (this.updateDependents?.length) return;
|
206
|
+
this.updateDependents = undefined;
|
207
|
+
this.hasChanged = true;
|
208
|
+
}
|
209
|
+
shouldOverrideUpdateDependents() {
|
210
|
+
return this.overrideUpdateDependents;
|
211
|
+
}
|
212
|
+
/**
|
213
|
+
* !!! important !!!
|
214
|
+
* this should get called only on a "temp lane", such as running "bit _snap", which the scope gets destroys after the
|
215
|
+
* command is done. when _scope exports the lane, this "overrideUpdateDependents" is not saved to the remote-scope.
|
216
|
+
*
|
217
|
+
* on a user local lane object, this prop should never be true. otherwise, it'll override the remote-scope data.
|
218
|
+
*/
|
219
|
+
setOverrideUpdateDependents(overrideUpdateDependents: boolean) {
|
220
|
+
this.overrideUpdateDependents = overrideUpdateDependents;
|
221
|
+
this.hasChanged = true;
|
222
|
+
}
|
223
|
+
|
224
|
+
removeComponent(id: ComponentID): boolean {
|
225
|
+
const existsComponent = this.getComponent(id);
|
226
|
+
if (!existsComponent) return false;
|
227
|
+
this.components = this.components.filter((c) => !c.id.isEqualWithoutVersion(id));
|
228
|
+
this.hasChanged = true;
|
229
|
+
return true;
|
230
|
+
}
|
231
|
+
getComponent(id: ComponentID): LaneComponent | undefined {
|
232
|
+
return this.components.find((c) => c.id.isEqualWithoutVersion(id));
|
233
|
+
}
|
234
|
+
getComponentHead(bitId: ComponentID): Ref | null {
|
235
|
+
const found = this.components.find((c) => c.id.isEqual(bitId));
|
236
|
+
if (found) return found.head;
|
237
|
+
return null;
|
238
|
+
}
|
239
|
+
setLaneComponents(laneComponents: LaneComponent[]) {
|
240
|
+
// this gets called when adding lane-components from other lanes/remotes, so it's better to
|
241
|
+
// clone the objects to not change the original data.
|
242
|
+
this.components = laneComponents.map((c) => ({ id: c.id.clone(), head: c.head.clone() }));
|
243
|
+
this.hasChanged = true;
|
244
|
+
}
|
245
|
+
setReadmeComponent(id?: ComponentID) {
|
246
|
+
const previousReadme = this.readmeComponent;
|
247
|
+
if (!id) {
|
248
|
+
this.readmeComponent = undefined;
|
249
|
+
if (previousReadme) this.hasChanged = true;
|
250
|
+
return;
|
251
|
+
}
|
252
|
+
const readmeComponent = this.getComponent(id);
|
253
|
+
if (!readmeComponent) {
|
254
|
+
this.readmeComponent = { id, head: null };
|
255
|
+
} else {
|
256
|
+
this.readmeComponent = readmeComponent;
|
257
|
+
}
|
258
|
+
if (
|
259
|
+
!previousReadme ||
|
260
|
+
!previousReadme.id.isEqual(id) ||
|
261
|
+
previousReadme.head?.toString() !== this.readmeComponent.head?.toString()
|
262
|
+
) {
|
263
|
+
this.hasChanged = true;
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
async isFullyMerged(scope: Scope): Promise<boolean> {
|
268
|
+
const { unmerged } = await this.getMergedAndUnmergedIds(scope);
|
269
|
+
return unmerged.length === 0;
|
270
|
+
}
|
271
|
+
async getMergedAndUnmergedIds(scope: Scope): Promise<{ merged: ComponentID[]; unmerged: ComponentID[] }> {
|
272
|
+
const merged: ComponentID[] = [];
|
273
|
+
const unmerged: ComponentID[] = [];
|
274
|
+
await Promise.all(
|
275
|
+
this.components.map(async (component) => {
|
276
|
+
const modelComponent = await scope.getModelComponentIfExist(component.id);
|
277
|
+
if (!modelComponent) {
|
278
|
+
unmerged.push(component.id);
|
279
|
+
return;
|
280
|
+
}
|
281
|
+
const startTraverseFrom = modelComponent.getHead() || null; // it's important to have it as null and not as undefined, see hasVersionByRef
|
282
|
+
const headExist = await hasVersionByRef(modelComponent, component.head, scope.objects, startTraverseFrom);
|
283
|
+
if (headExist) merged.push(component.id);
|
284
|
+
else unmerged.push(component.id);
|
285
|
+
})
|
286
|
+
);
|
287
|
+
return { merged, unmerged };
|
288
|
+
}
|
289
|
+
/**
|
290
|
+
* @deprecated use toComponentIds instead
|
291
|
+
*/
|
292
|
+
toBitIds(): ComponentIdList {
|
293
|
+
return this.toComponentIds();
|
294
|
+
}
|
295
|
+
toComponentIds(): ComponentIdList {
|
296
|
+
return ComponentIdList.fromArray(this.components.map((c) => c.id.changeVersion(c.head.toString())));
|
297
|
+
}
|
298
|
+
toComponentIdsIncludeUpdateDependents(): ComponentIdList {
|
299
|
+
return ComponentIdList.fromArray(this.toComponentIds().concat(this.updateDependents || []));
|
300
|
+
}
|
301
|
+
toLaneId() {
|
302
|
+
return new LaneId({ scope: this.scope, name: this.name });
|
303
|
+
}
|
304
|
+
collectObjectsById(repo: Repository): Promise<Array<{ id: ComponentID; objects: BitObject[] }>> {
|
305
|
+
return Promise.all(
|
306
|
+
this.components.map(async (component) => {
|
307
|
+
const headVersion = (await component.head.load(repo)) as Version;
|
308
|
+
const objects = [headVersion, ...headVersion.collect(repo)];
|
309
|
+
return { id: component.id, objects };
|
310
|
+
})
|
311
|
+
);
|
312
|
+
}
|
313
|
+
includeDeletedData(): boolean {
|
314
|
+
return gte(this.schema, SCHEMA_INCLUDING_DELETED_COMPONENTS_DATA);
|
315
|
+
}
|
316
|
+
setSchemaToSupportDeletedData() {
|
317
|
+
this.schema = SCHEMA_INCLUDING_DELETED_COMPONENTS_DATA;
|
318
|
+
this.hasChanged = true;
|
319
|
+
}
|
320
|
+
setSchemaToNotSupportDeletedData() {
|
321
|
+
this.schema = OLD_LANE_SCHEMA;
|
322
|
+
this.hasChanged = true;
|
323
|
+
}
|
324
|
+
getCompHeadIncludeUpdateDependents(componentId: ComponentID): Ref | undefined {
|
325
|
+
const comp = this.getComponent(componentId);
|
326
|
+
if (comp) return comp.head;
|
327
|
+
const fromUpdateDependents = this.updateDependents?.find((c) => c.isEqualWithoutVersion(componentId));
|
328
|
+
if (fromUpdateDependents) return Ref.from(fromUpdateDependents.version);
|
329
|
+
return undefined;
|
330
|
+
}
|
331
|
+
validate() {
|
332
|
+
const message = `unable to save Lane object "${this.id()}"`;
|
333
|
+
const bitIds = this.toComponentIds();
|
334
|
+
this.components.forEach((component) => {
|
335
|
+
if (bitIds.filterWithoutVersion(component.id).length > 1) {
|
336
|
+
throw new ValidationError(`${message}, the following component is duplicated "${component.id.fullName}"`);
|
337
|
+
}
|
338
|
+
if (!isSnap(component.head.hash)) {
|
339
|
+
throw new ValidationError(
|
340
|
+
`${message}, lane component ${component.id.toStringWithoutVersion()} head should be a hash, got ${
|
341
|
+
component.head.hash
|
342
|
+
}`
|
343
|
+
);
|
344
|
+
}
|
345
|
+
});
|
346
|
+
if (this.name === DEFAULT_LANE) {
|
347
|
+
throw new BitError(`${message}, this name is reserved as the default lane`);
|
348
|
+
}
|
349
|
+
if (this.name === PREVIOUS_DEFAULT_LANE) {
|
350
|
+
throw new BitError(`${message}, this name is reserved as the old default lane`);
|
351
|
+
}
|
352
|
+
}
|
353
|
+
isEqual(lane: Lane): boolean {
|
354
|
+
if (this.id() !== lane.id()) return false;
|
355
|
+
const thisComponents = this.toComponentIds().toStringArray().sort();
|
356
|
+
const otherComponents = lane.toComponentIds().toStringArray().sort();
|
357
|
+
return isEqual(thisComponents, otherComponents);
|
358
|
+
}
|
359
|
+
clone() {
|
360
|
+
return new Lane({
|
361
|
+
...this,
|
362
|
+
hash: this._hash,
|
363
|
+
overrideUpdateDependents: this.overrideUpdateDependents,
|
364
|
+
components: cloneDeep(this.components),
|
365
|
+
});
|
366
|
+
}
|
367
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import { expect } from 'chai';
|
2
|
+
|
3
|
+
import ModelComponent from './model-component';
|
4
|
+
import { clone } from 'lodash';
|
5
|
+
|
6
|
+
const modelComponentFixture = {
|
7
|
+
name: 'bar/foo',
|
8
|
+
scope: 'remote-scope',
|
9
|
+
versions: {
|
10
|
+
'0.0.1': '125a37bdb17220bdc1406a9a28a3dde4eec91225',
|
11
|
+
},
|
12
|
+
lang: 'javascript',
|
13
|
+
deprecated: false,
|
14
|
+
bindingPrefix: '@bit',
|
15
|
+
remotes: [
|
16
|
+
{
|
17
|
+
url: 'file:///tmp/remote-scope',
|
18
|
+
name: 'remote-scope',
|
19
|
+
date: '1572532837438',
|
20
|
+
},
|
21
|
+
],
|
22
|
+
state: {
|
23
|
+
versions: {
|
24
|
+
'0.0.1': {
|
25
|
+
local: true,
|
26
|
+
},
|
27
|
+
},
|
28
|
+
},
|
29
|
+
};
|
30
|
+
|
31
|
+
const getModelComponentFixture = (): typeof modelComponentFixture => {
|
32
|
+
return clone(modelComponentFixture);
|
33
|
+
};
|
34
|
+
|
35
|
+
const getModelComponent = (obj: object): ModelComponent => {
|
36
|
+
return ModelComponent.parse(JSON.stringify(obj));
|
37
|
+
};
|
38
|
+
|
39
|
+
describe('ModelComponent', () => {
|
40
|
+
describe('validate', () => {
|
41
|
+
let validateFunc: Function;
|
42
|
+
describe('duplicate hashes', () => {
|
43
|
+
let modelComponent: ModelComponent;
|
44
|
+
before(() => {
|
45
|
+
const fixture = getModelComponentFixture();
|
46
|
+
fixture.versions['0.0.2'] = fixture.versions['0.0.1'];
|
47
|
+
modelComponent = getModelComponent(fixture);
|
48
|
+
validateFunc = () => modelComponent.validate();
|
49
|
+
});
|
50
|
+
it('should throw an error', () => {
|
51
|
+
expect(validateFunc).to.throw('the following hash(es) are duplicated');
|
52
|
+
});
|
53
|
+
});
|
54
|
+
});
|
55
|
+
});
|