@teambit/lanes 1.0.106 → 1.0.108

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.
@@ -0,0 +1,28 @@
1
+ import { Route, Verb, Request, Response } from '@teambit/express';
2
+ import { Logger } from '@teambit/logger';
3
+ import { LanesMain } from './lanes.main.runtime';
4
+
5
+ export class LanesRestoreRoute implements Route {
6
+ constructor(private lanes: LanesMain, private logger: Logger) {}
7
+
8
+ method = 'post';
9
+ route = this.lanes.restoreRoutePath;
10
+ verb = Verb.WRITE;
11
+
12
+ middlewares = [
13
+ async (req: Request, res: Response) => {
14
+ const { body } = req;
15
+ const laneHash = body.hash;
16
+ if (!laneHash) {
17
+ return res.status(400).send('Missing hash in body');
18
+ }
19
+ try {
20
+ const result = await this.lanes.restoreLane(laneHash);
21
+ return res.json(result);
22
+ } catch (e: any) {
23
+ this.logger.error(e.toString());
24
+ return res.status(500).send(e.toString());
25
+ }
26
+ },
27
+ ];
28
+ }
package/lanes.spec.ts ADDED
@@ -0,0 +1,201 @@
1
+ import { loadAspect } from '@teambit/harmony.testing.load-aspect';
2
+ import SnappingAspect, { SnappingMain } from '@teambit/snapping';
3
+ import { ExportAspect, ExportMain } from '@teambit/export';
4
+ import { mockWorkspace, destroyWorkspace, WorkspaceData } from '@teambit/workspace.testing.mock-workspace';
5
+ import { mockComponents, modifyMockedComponents } from '@teambit/component.testing.mock-components';
6
+ import { ChangeType } from '@teambit/lanes.entities.lane-diff';
7
+ import { LanesAspect } from './lanes.aspect';
8
+ import { LanesMain } from './lanes.main.runtime';
9
+
10
+ describe('LanesAspect', function () {
11
+ describe('getLanes()', () => {
12
+ let lanes: LanesMain;
13
+ let workspaceData: WorkspaceData;
14
+ beforeAll(async () => {
15
+ workspaceData = mockWorkspace();
16
+ const { workspacePath } = workspaceData;
17
+ await mockComponents(workspacePath);
18
+ lanes = await loadAspect(LanesAspect, workspacePath);
19
+ await lanes.createLane('stage');
20
+ }, 30000);
21
+ afterAll(async () => {
22
+ await destroyWorkspace(workspaceData);
23
+ });
24
+ it('should list all lanes', async () => {
25
+ const currentLanes = await lanes.getLanes({});
26
+ expect(currentLanes.length).toEqual(1);
27
+ expect(currentLanes[0].name).toEqual('stage');
28
+ });
29
+ });
30
+
31
+ describe('isLaneUpToDate', () => {
32
+ let lanes: LanesMain;
33
+ let snapping: SnappingMain;
34
+ let workspaceData: WorkspaceData;
35
+ beforeAll(async () => {
36
+ workspaceData = mockWorkspace();
37
+ const { workspacePath } = workspaceData;
38
+ await mockComponents(workspacePath);
39
+ snapping = await loadAspect(SnappingAspect, workspacePath);
40
+ await snapping.tag({ ids: ['comp1'], build: false, ignoreIssues: 'MissingManuallyConfiguredPackages' });
41
+ const exporter: ExportMain = await loadAspect(ExportAspect, workspacePath);
42
+ await exporter.export();
43
+ lanes = await loadAspect(LanesAspect, workspacePath);
44
+ await lanes.createLane('stage');
45
+ await modifyMockedComponents(workspacePath, 'v2');
46
+ const result = await snapping.snap({
47
+ pattern: 'comp1',
48
+ build: false,
49
+ ignoreIssues: 'MissingManuallyConfiguredPackages',
50
+ });
51
+ // intermediate step, make sure it is snapped
52
+ expect(result?.snappedComponents.length).toEqual(1);
53
+ }, 30000);
54
+ afterAll(async () => {
55
+ await destroyWorkspace(workspaceData);
56
+ });
57
+ it('should return that the lane is up to date when the lane is ahead of main', async () => {
58
+ const currentLane = await lanes.getCurrentLane();
59
+ if (!currentLane) throw new Error('unable to get the current lane');
60
+ const isUpToDate = (
61
+ await lanes.diffStatus(currentLane.toLaneId(), undefined, { skipChanges: true })
62
+ ).componentsStatus.every((c) => c.upToDate);
63
+
64
+ expect(isUpToDate).toEqual(true);
65
+ });
66
+ it('should return that the lane is not up to date when main is ahead', async () => {
67
+ const currentLane = await lanes.getCurrentLane();
68
+ if (!currentLane) throw new Error('unable to get the current lane');
69
+ await lanes.switchLanes('main', { skipDependencyInstallation: true });
70
+ await snapping.snap({
71
+ pattern: 'comp1',
72
+ build: false,
73
+ unmodified: true,
74
+ ignoreIssues: 'MissingManuallyConfiguredPackages',
75
+ });
76
+ const isUpToDate = (
77
+ await lanes.diffStatus(currentLane.toLaneId(), undefined, { skipChanges: true })
78
+ ).componentsStatus.every((c) => c.upToDate);
79
+
80
+ expect(isUpToDate).toEqual(false);
81
+ });
82
+ });
83
+
84
+ describe('laneDiff', () => {
85
+ let lanes: LanesMain;
86
+ let snapping: SnappingMain;
87
+ let workspaceData: WorkspaceData;
88
+ beforeAll(async () => {
89
+ workspaceData = mockWorkspace();
90
+ const { workspacePath } = workspaceData;
91
+ await mockComponents(workspacePath);
92
+ snapping = await loadAspect(SnappingAspect, workspacePath);
93
+ await snapping.tag({ ids: ['comp1'], build: false });
94
+ const exporter: ExportMain = await loadAspect(ExportAspect, workspacePath);
95
+ await exporter.export();
96
+ lanes = await loadAspect(LanesAspect, workspacePath);
97
+ await lanes.createLane('stage');
98
+ const result = await snapping.snap({ pattern: 'comp1', build: false, unmodified: true });
99
+ // intermediate step, make sure it is snapped
100
+ expect(result?.snappedComponents.length).toEqual(1);
101
+ }, 30000);
102
+ afterAll(async () => {
103
+ await destroyWorkspace(workspaceData);
104
+ });
105
+ it('should return that the lane is up to date when the lane is ahead of main', async () => {
106
+ const currentLane = await lanes.getCurrentLane();
107
+ if (!currentLane) throw new Error('unable to get the current lane');
108
+ const laneDiffResults = await lanes.diffStatus(currentLane.toLaneId());
109
+ expect(laneDiffResults.componentsStatus[0].upToDate).toEqual;
110
+ expect(laneDiffResults.componentsStatus[0].changeType).toEqual(ChangeType.NONE);
111
+ });
112
+ it('should return that the lane is not up to date when main is ahead', async () => {
113
+ const currentLane = await lanes.getCurrentLane();
114
+ if (!currentLane) throw new Error('unable to get the current lane');
115
+ await lanes.switchLanes('main', { skipDependencyInstallation: true });
116
+ await snapping.snap({ pattern: 'comp1', build: false, unmodified: true });
117
+
118
+ const laneDiffResults = await lanes.diffStatus(currentLane.toLaneId());
119
+ expect(laneDiffResults.componentsStatus[0].upToDate).toEqual(false);
120
+ expect(laneDiffResults.componentsStatus[0].changeType).toEqual(ChangeType.NONE);
121
+ });
122
+ });
123
+
124
+ describe('restoreLane()', () => {
125
+ let lanes: LanesMain;
126
+ let workspaceData: WorkspaceData;
127
+ beforeAll(async () => {
128
+ workspaceData = mockWorkspace();
129
+ const { workspacePath } = workspaceData;
130
+ await mockComponents(workspacePath);
131
+ lanes = await loadAspect(LanesAspect, workspacePath);
132
+ await lanes.createLane('stage');
133
+
134
+ // as an intermediate step, make sure the lane was created
135
+ const currentLanes = await lanes.getLanes({});
136
+ expect(currentLanes.length).toEqual(1);
137
+
138
+ await lanes.switchLanes('main', { skipDependencyInstallation: true });
139
+ await lanes.removeLanes(['stage']);
140
+
141
+ // as an intermediate step, make sure the lane was removed
142
+ const lanesAfterDelete = await lanes.getLanes({});
143
+ expect(lanesAfterDelete.length).toEqual(0);
144
+
145
+ await lanes.restoreLane(currentLanes[0].hash);
146
+ }, 30000);
147
+ afterAll(async () => {
148
+ await destroyWorkspace(workspaceData);
149
+ });
150
+ it('should restore the deleted lane', async () => {
151
+ const currentLanes = await lanes.getLanes({});
152
+ expect(currentLanes.length).toEqual(1);
153
+ expect(currentLanes[0].id.name).toEqual('stage');
154
+ });
155
+ describe('delete restored lane', () => {
156
+ let output: string[];
157
+ beforeAll(async () => {
158
+ output = await lanes.removeLanes(['stage']);
159
+ });
160
+ it('should not throw', () => {
161
+ expect(output.length).toEqual(1);
162
+ });
163
+ });
164
+ });
165
+
166
+ describe('restore lane when an existing lane has the same id', () => {
167
+ let lanes: LanesMain;
168
+ let workspaceData: WorkspaceData;
169
+ let laneHash: string;
170
+ beforeAll(async () => {
171
+ workspaceData = mockWorkspace();
172
+ const { workspacePath } = workspaceData;
173
+ await mockComponents(workspacePath);
174
+ lanes = await loadAspect(LanesAspect, workspacePath);
175
+ await lanes.createLane('stage');
176
+
177
+ // as an intermediate step, make sure the lane was created
178
+ const currentLanes = await lanes.getLanes({});
179
+ expect(currentLanes.length).toEqual(1);
180
+
181
+ await lanes.switchLanes('main', { skipDependencyInstallation: true });
182
+ await lanes.removeLanes(['stage']);
183
+
184
+ await lanes.createLane('stage');
185
+ laneHash = currentLanes[0].hash;
186
+ }, 30000);
187
+ afterAll(async () => {
188
+ await destroyWorkspace(workspaceData);
189
+ });
190
+ it('should throw when restoring the lane', async () => {
191
+ let error: Error | undefined;
192
+ try {
193
+ await lanes.restoreLane(laneHash);
194
+ } catch (err: any) {
195
+ error = err;
196
+ }
197
+ expect(error).toBeInstanceOf(Error);
198
+ expect(error?.message).toMatch(/unable to restore lane/);
199
+ });
200
+ });
201
+ });
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@teambit/lanes",
3
- "version": "1.0.106",
3
+ "version": "1.0.108",
4
4
  "homepage": "https://bit.cloud/teambit/lanes/lanes",
5
5
  "main": "dist/index.js",
6
6
  "componentId": {
7
7
  "scope": "teambit.lanes",
8
8
  "name": "lanes",
9
- "version": "1.0.106"
9
+ "version": "1.0.108"
10
10
  },
11
11
  "dependencies": {
12
12
  "lodash": "4.17.21",
@@ -16,8 +16,6 @@
16
16
  "graphql-tag": "2.12.1",
17
17
  "p-map-series": "2.1.0",
18
18
  "p-map": "4.0.0",
19
- "core-js": "^3.0.0",
20
- "@babel/runtime": "7.20.0",
21
19
  "@teambit/bit-error": "0.0.404",
22
20
  "@teambit/component-version": "1.0.3",
23
21
  "@teambit/lane-id": "0.0.311",
@@ -38,44 +36,40 @@
38
36
  "@teambit/ui-foundation.ui.menu": "0.0.502",
39
37
  "@teambit/ui-foundation.ui.react-router.slot-router": "0.0.506",
40
38
  "@teambit/ui-foundation.ui.react-router.use-query": "0.0.501",
41
- "@teambit/scope": "1.0.106",
42
- "@teambit/snapping": "1.0.106",
43
- "@teambit/workspace": "1.0.106",
44
- "@teambit/cli": "0.0.839",
45
- "@teambit/express": "0.0.938",
46
- "@teambit/logger": "0.0.932",
47
- "@teambit/graphql": "1.0.106",
48
- "@teambit/checkout": "1.0.106",
49
- "@teambit/component-compare": "1.0.106",
50
- "@teambit/component-writer": "1.0.106",
51
- "@teambit/component": "1.0.106",
52
- "@teambit/export": "1.0.106",
53
- "@teambit/importer": "1.0.106",
54
- "@teambit/lanes.entities.lane-diff": "0.0.164",
39
+ "@teambit/scope": "1.0.108",
40
+ "@teambit/snapping": "1.0.108",
41
+ "@teambit/workspace": "1.0.108",
42
+ "@teambit/cli": "0.0.840",
43
+ "@teambit/express": "0.0.939",
44
+ "@teambit/logger": "0.0.933",
45
+ "@teambit/graphql": "1.0.108",
46
+ "@teambit/checkout": "1.0.108",
47
+ "@teambit/component-compare": "1.0.108",
48
+ "@teambit/component-writer": "1.0.108",
49
+ "@teambit/component": "1.0.108",
50
+ "@teambit/export": "1.0.108",
51
+ "@teambit/importer": "1.0.108",
55
52
  "@teambit/lanes.modules.diff": "0.0.438",
56
- "@teambit/merging": "1.0.106",
57
- "@teambit/remove": "1.0.106",
58
- "@teambit/ui": "1.0.106"
53
+ "@teambit/merging": "1.0.108",
54
+ "@teambit/remove": "1.0.108",
55
+ "@teambit/lanes.entities.lane-diff": "0.0.164",
56
+ "@teambit/ui": "1.0.108"
59
57
  },
60
58
  "devDependencies": {
61
59
  "@types/lodash": "4.14.165",
62
- "@types/react": "^17.0.8",
63
- "@types/chai": "4.2.15",
64
- "chai": "4.3.0",
65
60
  "@types/mocha": "9.1.0",
66
- "@types/node": "12.20.4",
67
- "@types/react-dom": "^17.0.5",
68
- "@types/jest": "^26.0.0",
69
- "@types/testing-library__jest-dom": "5.9.5",
70
- "@teambit/component.testing.mock-components": "0.0.179",
71
- "@teambit/harmony.testing.load-aspect": "0.0.178",
61
+ "@types/jest": "^29.2.2",
62
+ "@types/testing-library__jest-dom": "^5.9.5",
63
+ "@teambit/harmony.envs.core-aspect-env": "0.0.13",
64
+ "@teambit/component.testing.mock-components": "0.0.180",
65
+ "@teambit/harmony.testing.load-aspect": "0.0.179",
72
66
  "@teambit/workspace.testing.mock-workspace": "0.0.18"
73
67
  },
74
68
  "peerDependencies": {
75
- "react-router-dom": "^6.0.0",
76
- "@teambit/legacy": "1.0.624",
77
- "react": "^16.8.0 || ^17.0.0",
78
- "react-dom": "^16.8.0 || ^17.0.0"
69
+ "react": "^17.0.0 || ^18.0.0",
70
+ "react-router-dom": "^6.8.1",
71
+ "@types/react": "^18.2.12",
72
+ "@teambit/legacy": "1.0.624"
79
73
  },
80
74
  "license": "Apache-2.0",
81
75
  "optionalDependencies": {},
@@ -89,7 +83,7 @@
89
83
  },
90
84
  "private": false,
91
85
  "engines": {
92
- "node": ">=12.22.0"
86
+ "node": ">=16.0.0"
93
87
  },
94
88
  "repository": {
95
89
  "type": "git",
@@ -98,12 +92,9 @@
98
92
  "keywords": [
99
93
  "bit",
100
94
  "bit-aspect",
95
+ "bit-core-aspect",
101
96
  "components",
102
97
  "collaboration",
103
- "web",
104
- "react",
105
- "react-components",
106
- "angular",
107
- "angular-components"
98
+ "web"
108
99
  ]
109
100
  }
@@ -0,0 +1,152 @@
1
+ import { Consumer } from '@teambit/legacy/dist/consumer';
2
+ import { LaneId, DEFAULT_LANE } from '@teambit/lane-id';
3
+ import { ComponentID, ComponentIdList } from '@teambit/component-id';
4
+ import { ApplyVersionResults } from '@teambit/merging';
5
+ import { Lane } from '@teambit/legacy/dist/scope/models';
6
+ import { CheckoutPropsLegacy, CheckoutProps } from '@teambit/checkout';
7
+ import { Workspace } from '@teambit/workspace';
8
+ import { Logger } from '@teambit/logger';
9
+ import { BitError } from '@teambit/bit-error';
10
+ import { LanesMain } from './lanes.main.runtime';
11
+ import { throwForStagedComponents } from './create-lane';
12
+
13
+ export type SwitchProps = {
14
+ laneName: string;
15
+ ids?: ComponentID[];
16
+ laneBitIds?: ComponentID[]; // only needed for the deprecated onLanesOnly prop. once this prop is removed, this prop can be removed as well.
17
+ pattern?: string;
18
+ existingOnWorkspaceOnly: boolean;
19
+ remoteLane?: Lane;
20
+ localTrackedLane?: string;
21
+ alias?: string;
22
+ };
23
+
24
+ export class LaneSwitcher {
25
+ private consumer: Consumer;
26
+ private laneIdToSwitchTo: LaneId; // populated by `this.populateSwitchProps()`
27
+ private laneToSwitchTo: Lane | undefined; // populated by `this.populateSwitchProps()`, if default-lane, it's undefined
28
+ constructor(
29
+ private workspace: Workspace,
30
+ private logger: Logger,
31
+ private switchProps: SwitchProps,
32
+ private checkoutProps: CheckoutPropsLegacy,
33
+ private Lanes: LanesMain
34
+ ) {
35
+ this.consumer = this.workspace.consumer;
36
+ }
37
+
38
+ async switch(): Promise<ApplyVersionResults> {
39
+ this.logger.setStatusLine(`switching lanes`);
40
+ if (this.workspace.isOnMain()) {
41
+ await throwForStagedComponents(this.consumer);
42
+ }
43
+ await this.populateSwitchProps();
44
+ const bitMapIds = this.workspace.consumer.bitmapIdsFromCurrentLaneIncludeRemoved;
45
+ const idsToSwitch = this.switchProps.ids || [];
46
+ const idsWithVersion = idsToSwitch.map((id) => {
47
+ const bitMapId = bitMapIds.searchWithoutVersion(id);
48
+ return bitMapId || id;
49
+ });
50
+ const ids = await this.workspace.resolveMultipleComponentIds(idsWithVersion);
51
+
52
+ const checkoutProps: CheckoutProps = {
53
+ ...this.checkoutProps,
54
+ ids,
55
+ allowAddingComponentsFromScope: true,
56
+ versionPerId: await this.workspace.resolveMultipleComponentIds(idsToSwitch),
57
+ lane: this.laneToSwitchTo,
58
+ };
59
+
60
+ const results = await this.Lanes.checkout.checkout(checkoutProps);
61
+
62
+ await this.saveLanesData();
63
+ await this.consumer.onDestroy('lane-switch');
64
+
65
+ return results;
66
+ }
67
+
68
+ private async populateSwitchProps() {
69
+ const laneId = await this.consumer.scope.lanes.parseLaneIdFromString(this.switchProps.laneName);
70
+
71
+ const localLane = await this.consumer.scope.loadLane(laneId);
72
+ const mainIds = await this.consumer.getIdsOfDefaultLane();
73
+ if (laneId.isDefault()) {
74
+ await this.populatePropsAccordingToDefaultLane();
75
+ this.switchProps.ids = mainIds;
76
+ } else {
77
+ const laneIds = localLane
78
+ ? this.populatePropsAccordingToLocalLane(localLane)
79
+ : await this.populatePropsAccordingToRemoteLane(laneId);
80
+ const idsOnLaneOnly = laneIds.filter((id) => !mainIds.find((i) => i.isEqualWithoutVersion(id)));
81
+ const idsOnMainOnly = mainIds.filter((id) => !laneIds.find((i) => i.isEqualWithoutVersion(id)));
82
+ this.switchProps.ids = [...idsOnMainOnly, ...laneIds];
83
+ this.switchProps.laneBitIds = idsOnLaneOnly;
84
+ }
85
+
86
+ if (this.switchProps.pattern) {
87
+ if (this.consumer.bitMap.getAllBitIdsFromAllLanes().length) {
88
+ // if the workspace is not empty, it's possible that it has components from lane-x, and is now switching
89
+ // partially to lane-y, while lane-y has the same components as lane-x. in which case, the user ends up with
90
+ // an invalid state of components from lane-x and lane-y together.
91
+ throw new BitError('error: use --pattern only when the workspace is empty');
92
+ }
93
+ const allIds = await this.workspace.resolveMultipleComponentIds(this.switchProps.ids || []);
94
+ const patternIds = await this.workspace.filterIdsFromPoolIdsByPattern(this.switchProps.pattern, allIds);
95
+ this.switchProps.ids = patternIds.map((id) => id);
96
+ }
97
+ }
98
+
99
+ private async populatePropsAccordingToRemoteLane(remoteLaneId: LaneId): Promise<ComponentID[]> {
100
+ this.laneIdToSwitchTo = remoteLaneId;
101
+ this.logger.debug(`populatePropsAccordingToRemoteLane, remoteLaneId: ${remoteLaneId.toString()}`);
102
+ this.throwForSwitchingToCurrentLane();
103
+ const remoteLane = await this.Lanes.fetchLaneWithItsComponents(remoteLaneId);
104
+ this.switchProps.laneName = remoteLaneId.name;
105
+ this.switchProps.localTrackedLane = this.consumer.scope.lanes.getAliasByLaneId(remoteLaneId) || undefined;
106
+ this.switchProps.remoteLane = remoteLane;
107
+ this.laneToSwitchTo = remoteLane;
108
+ this.logger.debug(`populatePropsAccordingToRemoteLane, completed`);
109
+ return remoteLane.components.map((l) => l.id.changeVersion(l.head.toString()));
110
+ }
111
+
112
+ private async populatePropsAccordingToDefaultLane() {
113
+ this.laneIdToSwitchTo = LaneId.from(DEFAULT_LANE, this.consumer.scope.name);
114
+ this.throwForSwitchingToCurrentLane();
115
+ }
116
+
117
+ private populatePropsAccordingToLocalLane(localLane: Lane): ComponentID[] {
118
+ this.laneIdToSwitchTo = localLane.toLaneId();
119
+ this.laneToSwitchTo = localLane;
120
+ this.throwForSwitchingToCurrentLane();
121
+ return localLane.components.map((c) => c.id.changeVersion(c.head.toString()));
122
+ }
123
+
124
+ private throwForSwitchingToCurrentLane() {
125
+ if (this.consumer.getCurrentLaneId().isEqual(this.laneIdToSwitchTo)) {
126
+ const laneIdStr = this.laneIdToSwitchTo.isDefault()
127
+ ? this.laneIdToSwitchTo.name
128
+ : this.laneIdToSwitchTo.toString();
129
+ throw new BitError(`already checked out to "${laneIdStr}".
130
+ to be up to date with the remote lane, please run "bit checkout head""`);
131
+ }
132
+ }
133
+
134
+ private async saveLanesData() {
135
+ const localLaneName = this.switchProps.alias || this.laneIdToSwitchTo.name;
136
+ if (this.switchProps.remoteLane) {
137
+ if (!this.switchProps.localTrackedLane) {
138
+ this.consumer.scope.lanes.trackLane({
139
+ localLane: localLaneName,
140
+ remoteLane: this.laneIdToSwitchTo.name,
141
+ remoteScope: this.laneIdToSwitchTo.scope,
142
+ });
143
+ }
144
+ }
145
+
146
+ this.consumer.setCurrentLane(this.laneIdToSwitchTo, !this.laneToSwitchTo?.isNew);
147
+ this.consumer.bitMap.syncWithIds(
148
+ ComponentIdList.fromArray(this.switchProps.ids || []),
149
+ ComponentIdList.fromArray(this.switchProps.laneBitIds || [])
150
+ );
151
+ }
152
+ }
package/switch.cmd.ts ADDED
@@ -0,0 +1,100 @@
1
+ import chalk from 'chalk';
2
+ import { applyVersionReport, installationErrorOutput, compilationErrorOutput } from '@teambit/merging';
3
+ import { Command, CommandOptions } from '@teambit/cli';
4
+ import { MergeStrategy } from '@teambit/legacy/dist/consumer/versions-ops/merge-version';
5
+ import { COMPONENT_PATTERN_HELP } from '@teambit/legacy/dist/constants';
6
+ import { LanesMain } from './lanes.main.runtime';
7
+
8
+ export class SwitchCmd implements Command {
9
+ name = 'switch <lane>';
10
+ description = `switch to the specified lane`;
11
+ extendedDescription = ``;
12
+ private = true;
13
+ alias = '';
14
+ arguments = [
15
+ {
16
+ name: 'lane',
17
+ description: 'lane-name or lane-id (if lane is not local) to switch to',
18
+ },
19
+ ];
20
+ options = [
21
+ [
22
+ 'n',
23
+ 'alias <string>',
24
+ "relevant when the specified lane is a remote lane. create a local alias for the lane (doesnt affect the lane's name on the remote",
25
+ ],
26
+ [
27
+ 'm',
28
+ 'merge [strategy]',
29
+ 'merge local changes with the checked out version. strategy should be "theirs", "ours" or "manual"',
30
+ ],
31
+ ['a', 'get-all', 'checkout all components in a lane, including those not currently in the workspace'],
32
+ ['x', 'skip-dependency-installation', 'do not install dependencies of the imported components'],
33
+ [
34
+ 'p',
35
+ 'pattern <component-pattern>',
36
+ `switch only the lane components matching the specified component-pattern. only works when the workspace is empty\n
37
+ ${COMPONENT_PATTERN_HELP}`,
38
+ ],
39
+ ['j', 'json', 'return the output as JSON'],
40
+ ] as CommandOptions;
41
+ loader = true;
42
+
43
+ constructor(private lanes: LanesMain) {}
44
+
45
+ async report(
46
+ [lane]: [string],
47
+ {
48
+ alias,
49
+ merge,
50
+ getAll = false,
51
+ skipDependencyInstallation = false,
52
+ pattern,
53
+ json = false,
54
+ }: {
55
+ alias?: string;
56
+ merge?: MergeStrategy;
57
+ getAll?: boolean;
58
+ skipDependencyInstallation?: boolean;
59
+ override?: boolean;
60
+ pattern?: string;
61
+ json?: boolean;
62
+ }
63
+ ) {
64
+ const { components, failedComponents, installationError, compilationError } = await this.lanes.switchLanes(lane, {
65
+ alias,
66
+ merge,
67
+ getAll,
68
+ pattern,
69
+ skipDependencyInstallation,
70
+ });
71
+ if (json) {
72
+ return JSON.stringify({ components, failedComponents }, null, 4);
73
+ }
74
+ const getFailureOutput = () => {
75
+ if (!failedComponents || !failedComponents.length) return '';
76
+ const title = 'the switch has been canceled for the following component(s)';
77
+ const body = failedComponents
78
+ .map((failedComponent) => {
79
+ const color = failedComponent.unchangedLegitimately ? 'white' : 'red';
80
+ return `${chalk.bold(failedComponent.id.toString())} - ${chalk[color](failedComponent.unchangedMessage)}`;
81
+ })
82
+ .join('\n');
83
+ return `${title}\n${body}\n\n`;
84
+ };
85
+ const getSuccessfulOutput = () => {
86
+ const laneSwitched = chalk.green(`\nsuccessfully set "${chalk.bold(lane)}" as the active lane`);
87
+ if (!components || !components.length) return `No components have been changed.${laneSwitched}`;
88
+ const title = `successfully switched ${components.length} components to the head of lane ${lane}\n`;
89
+ return chalk.bold(title) + applyVersionReport(components, true, false) + laneSwitched;
90
+ };
91
+ const failedOutput = getFailureOutput();
92
+ const successOutput = getSuccessfulOutput();
93
+ return (
94
+ failedOutput +
95
+ successOutput +
96
+ installationErrorOutput(installationError) +
97
+ compilationErrorOutput(compilationError)
98
+ );
99
+ }
100
+ }
package/tsconfig.json CHANGED
@@ -1,38 +1,33 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "lib": [
4
- "es2019",
5
- "DOM",
6
- "ES6",
7
- "DOM.Iterable",
8
- "ScriptHost"
4
+ "esnext",
5
+ "dom",
6
+ "dom.Iterable"
9
7
  ],
10
- "target": "es2015",
11
- "module": "CommonJS",
12
- "jsx": "react",
13
- "allowJs": true,
14
- "composite": true,
8
+ "target": "es2020",
9
+ "module": "es2020",
10
+ "jsx": "react-jsx",
15
11
  "declaration": true,
16
12
  "sourceMap": true,
17
- "skipLibCheck": true,
18
13
  "experimentalDecorators": true,
19
- "outDir": "dist",
14
+ "skipLibCheck": true,
20
15
  "moduleResolution": "node",
21
16
  "esModuleInterop": true,
22
- "rootDir": ".",
23
17
  "resolveJsonModule": true,
24
- "emitDeclarationOnly": true,
25
- "emitDecoratorMetadata": true,
26
- "allowSyntheticDefaultImports": true,
27
- "strictPropertyInitialization": false,
28
- "strict": true,
29
- "noImplicitAny": false,
30
- "preserveConstEnums": true
18
+ "allowJs": true,
19
+ "outDir": "dist",
20
+ "emitDeclarationOnly": true
31
21
  },
32
22
  "exclude": [
23
+ "artifacts",
24
+ "public",
33
25
  "dist",
26
+ "node_modules",
27
+ "package.json",
34
28
  "esm.mjs",
35
- "package.json"
29
+ "**/*.cjs",
30
+ "./dist"
36
31
  ],
37
32
  "include": [
38
33
  "**/*",