@teambit/workspace 1.0.108 → 1.0.110
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/preview/static/css/teambit.workspace/workspace-preview.0f99da04.css +55 -0
- package/artifacts/preview/static/images/2f046646df38433e90d7.png +0 -0
- package/artifacts/preview/static/images/b40d450de296e275550f.png +0 -0
- package/artifacts/preview/static/images/cb67fb802479e2710016.png +0 -0
- package/artifacts/preview/teambit_workspace_workspace-preview.js +2 -0
- package/dist/{preview-1703647408454.js → preview-1703733956734.js} +2 -2
- package/package.json +35 -31
- package/aspects-merger.ts +0 -319
- package/bit-map.ts +0 -277
- package/build-graph-from-fs.ts +0 -188
- package/build-graph-ids-from-fs.ts +0 -216
- package/capsule.cmd.ts +0 -217
- package/constants.ts +0 -1
- package/eject-conf.cmd.ts +0 -57
- package/filter.ts +0 -139
- package/index.ts +0 -22
- package/merge-conflict-file.ts +0 -129
- package/on-component-events.ts +0 -24
- package/pattern.cmd.ts +0 -53
- package/types.ts +0 -71
- package/use.cmd.ts +0 -25
- package/workspace-aspects-loader.ts +0 -885
- package/workspace-section.ts +0 -14
- package/workspace.aspect.ts +0 -9
- package/workspace.graphql.ts +0 -133
- package/workspace.main.runtime.ts +0 -56
- package/workspace.provider.ts +0 -282
- package/workspace.ts +0 -2014
- package/workspace.ui-root.ts +0 -65
package/capsule.cmd.ts
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line max-classes-per-file
|
|
2
|
-
import { Command, CommandOptions } from '@teambit/cli';
|
|
3
|
-
import { CapsuleList, IsolateComponentsOptions, IsolatorMain } from '@teambit/isolator';
|
|
4
|
-
import type { ScopeMain } from '@teambit/scope';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
|
|
7
|
-
import { Workspace } from '.';
|
|
8
|
-
|
|
9
|
-
type CreateOpts = {
|
|
10
|
-
baseDir?: string;
|
|
11
|
-
rootBaseDir?: string;
|
|
12
|
-
alwaysNew?: boolean;
|
|
13
|
-
seedersOnly?: boolean;
|
|
14
|
-
useHash?: boolean;
|
|
15
|
-
id: string;
|
|
16
|
-
installPackages?: boolean;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export class CapsuleCreateCmd implements Command {
|
|
20
|
-
name = 'create [component-id...]';
|
|
21
|
-
description = `create capsules for components`;
|
|
22
|
-
helpUrl = 'reference/build-pipeline/capsule';
|
|
23
|
-
group = 'capsules';
|
|
24
|
-
alias = '';
|
|
25
|
-
options = [
|
|
26
|
-
[
|
|
27
|
-
'b',
|
|
28
|
-
'base-dir <name>',
|
|
29
|
-
'set base dir of all capsules (hashed to create the base dir inside the root dir - host path by default)',
|
|
30
|
-
],
|
|
31
|
-
['r', 'root-base-dir <name>', 'set root base dir of all capsules (absolute path to use as root dir)'],
|
|
32
|
-
['a', 'always-new', 'create new environment for capsule'],
|
|
33
|
-
['s', 'seeders-only', 'create capsules for the seeders only (not for the entire graph)'],
|
|
34
|
-
['i', 'id <name>', 'reuse capsule of certain name'],
|
|
35
|
-
['', 'use-hash', 'whether to use hash function (of base dir) as capsules root dir name'],
|
|
36
|
-
['j', 'json', 'json format'],
|
|
37
|
-
['d', 'install-packages', 'install packages by the package-manager'],
|
|
38
|
-
['p', 'package-manager <name>', 'npm, yarn or pnpm, default to npm'],
|
|
39
|
-
] as CommandOptions;
|
|
40
|
-
|
|
41
|
-
constructor(private workspace: Workspace | undefined, private scope: ScopeMain, private isolator: IsolatorMain) {}
|
|
42
|
-
|
|
43
|
-
async create(
|
|
44
|
-
[componentIds = []]: [string[]],
|
|
45
|
-
{ baseDir, rootBaseDir, alwaysNew = false, id, installPackages = false, seedersOnly = false, useHash }: CreateOpts
|
|
46
|
-
): Promise<CapsuleList> {
|
|
47
|
-
// @todo: why it is not an array?
|
|
48
|
-
if (componentIds && !Array.isArray(componentIds)) componentIds = [componentIds];
|
|
49
|
-
let finalUseHash = useHash;
|
|
50
|
-
if (useHash === undefined) {
|
|
51
|
-
if (baseDir) {
|
|
52
|
-
finalUseHash = false;
|
|
53
|
-
} else {
|
|
54
|
-
finalUseHash = this.workspace
|
|
55
|
-
? this.workspace?.shouldUseHashForCapsules()
|
|
56
|
-
: this.scope.shouldUseHashForCapsules();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const baseInstallOptions = { installPackages };
|
|
61
|
-
const additionalInstallOptions = this.workspace
|
|
62
|
-
? {}
|
|
63
|
-
: {
|
|
64
|
-
copyPeerToRuntimeOnRoot: true,
|
|
65
|
-
useNesting: true,
|
|
66
|
-
copyPeerToRuntimeOnComponents: true,
|
|
67
|
-
installPeersFromEnvs: true,
|
|
68
|
-
};
|
|
69
|
-
const installOptions = { ...baseInstallOptions, ...additionalInstallOptions };
|
|
70
|
-
|
|
71
|
-
const capsuleOptions: IsolateComponentsOptions = {
|
|
72
|
-
baseDir,
|
|
73
|
-
rootBaseDir,
|
|
74
|
-
installOptions,
|
|
75
|
-
alwaysNew,
|
|
76
|
-
seedersOnly,
|
|
77
|
-
includeFromNestedHosts: true,
|
|
78
|
-
name: id,
|
|
79
|
-
useHash: finalUseHash,
|
|
80
|
-
};
|
|
81
|
-
const host = this.workspace || this.scope;
|
|
82
|
-
const ids = await host.resolveMultipleComponentIds(componentIds);
|
|
83
|
-
const network = await this.isolator.isolateComponents(ids, capsuleOptions);
|
|
84
|
-
const capsules = network.graphCapsules;
|
|
85
|
-
return capsules;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async report([componentIds]: [string[]], opts: CreateOpts) {
|
|
89
|
-
// @ts-ignore
|
|
90
|
-
const capsules = await this.create(componentIds, opts);
|
|
91
|
-
const capsuleOutput = capsules
|
|
92
|
-
.map((capsule) => `${chalk.bold(capsule.component.id.toString())} - ${capsule.path}`)
|
|
93
|
-
.join('\n');
|
|
94
|
-
const title = `${capsules.length} capsule(s) were created successfully`;
|
|
95
|
-
return `${chalk.green(title)}\n${capsuleOutput}`;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async json([componentIds]: [string[]], opts: CreateOpts) {
|
|
99
|
-
// @ts-ignore
|
|
100
|
-
const capsules = await this.create(componentIds, opts);
|
|
101
|
-
return capsules.map((c) => ({
|
|
102
|
-
id: c.component.id.toString(),
|
|
103
|
-
path: c.path,
|
|
104
|
-
}));
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export class CapsuleListCmd implements Command {
|
|
109
|
-
name = 'list';
|
|
110
|
-
description = `list the capsules generated for this workspace`;
|
|
111
|
-
group = 'capsules';
|
|
112
|
-
alias = '';
|
|
113
|
-
options = [['j', 'json', 'json format']] as CommandOptions;
|
|
114
|
-
|
|
115
|
-
constructor(private isolator: IsolatorMain, private workspace: Workspace | undefined, private scope: ScopeMain) {}
|
|
116
|
-
|
|
117
|
-
async report() {
|
|
118
|
-
const { workspaceCapsulesRootDir, scopeAspectsCapsulesRootDir } = this.getCapsulesRootDirs();
|
|
119
|
-
const listWs = workspaceCapsulesRootDir ? await this.isolator.list(workspaceCapsulesRootDir) : undefined;
|
|
120
|
-
const listScope = await this.isolator.list(scopeAspectsCapsulesRootDir);
|
|
121
|
-
|
|
122
|
-
const hostPath = this.workspace ? this.workspace.path : this.scope.path;
|
|
123
|
-
const numOfWsCapsules = listWs ? listWs.capsules.length : listScope.capsules.length;
|
|
124
|
-
const hostType = this.workspace ? 'workspace' : 'scope';
|
|
125
|
-
|
|
126
|
-
const title = chalk.green(
|
|
127
|
-
`found ${chalk.cyan(numOfWsCapsules.toString())} capsule(s) for ${hostType}: ${chalk.cyan(hostPath)}`
|
|
128
|
-
);
|
|
129
|
-
const wsLine = listWs
|
|
130
|
-
? chalk.green(`workspace capsules root-dir: ${chalk.cyan(workspaceCapsulesRootDir)}`)
|
|
131
|
-
: undefined;
|
|
132
|
-
const scopeLine = chalk.green(`scope's aspects capsules root-dir: ${chalk.cyan(scopeAspectsCapsulesRootDir)}`);
|
|
133
|
-
const suggestLine = chalk.green(`use --json to get the list of all capsules`);
|
|
134
|
-
const lines = [title, wsLine, scopeLine, suggestLine].filter((x) => x).join('\n');
|
|
135
|
-
|
|
136
|
-
// TODO: improve output
|
|
137
|
-
return lines;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async json() {
|
|
141
|
-
const rootDirs = this.getCapsulesRootDirs();
|
|
142
|
-
const listWs = rootDirs.workspaceCapsulesRootDir
|
|
143
|
-
? await this.isolator.list(rootDirs.workspaceCapsulesRootDir)
|
|
144
|
-
: undefined;
|
|
145
|
-
const listScope = await this.isolator.list(rootDirs.scopeAspectsCapsulesRootDir);
|
|
146
|
-
const capsules = listWs ? listWs.capsules : [];
|
|
147
|
-
const scopeCapsules = listScope ? listScope.capsules : [];
|
|
148
|
-
return { ...rootDirs, capsules, scopeCapsules };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private getCapsulesRootDirs() {
|
|
152
|
-
return getCapsulesRootDirs(this.isolator, this.scope, this.workspace);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export class CapsuleDeleteCmd implements Command {
|
|
157
|
-
name = 'delete';
|
|
158
|
-
description = `delete capsules`;
|
|
159
|
-
extendedDescription = `with no args, only workspace's capsules are deleted`;
|
|
160
|
-
group = 'capsules';
|
|
161
|
-
alias = '';
|
|
162
|
-
options = [
|
|
163
|
-
['', 'scope-aspects', 'delete scope-aspects capsules'],
|
|
164
|
-
['a', 'all', 'delete all capsules for all workspaces and scopes'],
|
|
165
|
-
] as CommandOptions;
|
|
166
|
-
|
|
167
|
-
constructor(private isolator: IsolatorMain, private scope: ScopeMain, private workspace?: Workspace) {}
|
|
168
|
-
|
|
169
|
-
async report(args: [], { all, scopeAspects }: { all: boolean; scopeAspects: boolean }) {
|
|
170
|
-
const capsuleBaseDirToDelete = (): string | undefined => {
|
|
171
|
-
if (all) return undefined;
|
|
172
|
-
if (scopeAspects) {
|
|
173
|
-
const { scopeAspectsCapsulesRootDir } = getCapsulesRootDirs(this.isolator, this.scope, this.workspace);
|
|
174
|
-
return scopeAspectsCapsulesRootDir;
|
|
175
|
-
}
|
|
176
|
-
return undefined;
|
|
177
|
-
};
|
|
178
|
-
const capsuleBaseDir = capsuleBaseDirToDelete();
|
|
179
|
-
const deletedDir = await this.isolator.deleteCapsules(capsuleBaseDir);
|
|
180
|
-
return chalk.green(`the following capsules dir has been deleted ${chalk.bold(deletedDir)}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export class CapsuleCmd implements Command {
|
|
185
|
-
name = 'capsule';
|
|
186
|
-
description = 'manage capsules';
|
|
187
|
-
extendedDescription = `a capsule is a directory containing the component code, isolated from the workspace.
|
|
188
|
-
normally, capsules are created during the build process, the component files are copied and the packages are installed
|
|
189
|
-
via the configured package-manager. the purpose is to compile/test them in isolation to make sure they will work for
|
|
190
|
-
other users after publishing/exporting them.`;
|
|
191
|
-
alias = '';
|
|
192
|
-
group = 'capsules';
|
|
193
|
-
commands: Command[] = [];
|
|
194
|
-
options = [['j', 'json', 'json format']] as CommandOptions;
|
|
195
|
-
|
|
196
|
-
constructor(private isolator: IsolatorMain, private workspace: Workspace | undefined, private scope: ScopeMain) {}
|
|
197
|
-
|
|
198
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
199
|
-
async report(args: [string]) {
|
|
200
|
-
return new CapsuleListCmd(this.isolator, this.workspace, this.scope).report();
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function getCapsulesRootDirs(isolator, scope, workspace) {
|
|
205
|
-
const workspaceCapsulesRootDir = workspace
|
|
206
|
-
? isolator.getCapsulesRootDir({
|
|
207
|
-
baseDir: workspace.getCapsulePath(),
|
|
208
|
-
useHash: workspace.shouldUseHashForCapsules(),
|
|
209
|
-
})
|
|
210
|
-
: undefined;
|
|
211
|
-
const scopeAspectsCapsulesRootDir = isolator.getCapsulesRootDir({
|
|
212
|
-
baseDir: scope.getAspectCapsulePath(),
|
|
213
|
-
useHash: scope.shouldUseHashForCapsules(),
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
return { workspaceCapsulesRootDir, scopeAspectsCapsulesRootDir };
|
|
217
|
-
}
|
package/constants.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const EXT_NAME = 'teambit.workspace/workspace';
|
package/eject-conf.cmd.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { Command, CommandOptions } from '@teambit/cli';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { PATTERN_HELP } from '@teambit/legacy/dist/constants';
|
|
5
|
-
|
|
6
|
-
import { EjectConfOptions, EjectConfResult, Workspace } from './workspace';
|
|
7
|
-
|
|
8
|
-
type EjectConfArgs = [string];
|
|
9
|
-
// From the cli we might get those as string in case we run it like --propagate true (return string) as opposed to only --propagate
|
|
10
|
-
type EjectConfOptionsCLI = {
|
|
11
|
-
propagate: string | boolean | undefined;
|
|
12
|
-
override: string | boolean | undefined;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default class EjectConfCmd implements Command {
|
|
16
|
-
name = 'eject-conf <pattern>';
|
|
17
|
-
description = 'eject components configuration (create a `component.json` file)';
|
|
18
|
-
extendedDescription = `note this can be reversed at any time by snapping/tagging changes and deleting the component.json file \n${PATTERN_HELP(
|
|
19
|
-
'eject-conf'
|
|
20
|
-
)}`;
|
|
21
|
-
alias = '';
|
|
22
|
-
group = 'development';
|
|
23
|
-
options = [
|
|
24
|
-
[
|
|
25
|
-
'p',
|
|
26
|
-
'propagate',
|
|
27
|
-
'mark propagate true in the config file, so that component.json configs will be merge with workspace configs',
|
|
28
|
-
],
|
|
29
|
-
['o', 'override', 'override file if exist'],
|
|
30
|
-
] as CommandOptions;
|
|
31
|
-
|
|
32
|
-
constructor(private workspace: Workspace) {}
|
|
33
|
-
|
|
34
|
-
async report(args: EjectConfArgs, options: EjectConfOptionsCLI): Promise<string> {
|
|
35
|
-
const ejectResult = await this.json(args, options);
|
|
36
|
-
const paths = ejectResult
|
|
37
|
-
.map((result) => result.configPath)
|
|
38
|
-
.map((p) => path.relative(this.workspace.path, p))
|
|
39
|
-
.join('\n');
|
|
40
|
-
return chalk.green(`successfully ejected config to the following path(s)
|
|
41
|
-
${chalk.bold(paths)}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async json([pattern]: EjectConfArgs, options: EjectConfOptionsCLI): Promise<EjectConfResult[]> {
|
|
45
|
-
const ejectOptions = options;
|
|
46
|
-
if (ejectOptions.propagate === 'true') {
|
|
47
|
-
ejectOptions.propagate = true;
|
|
48
|
-
}
|
|
49
|
-
if (ejectOptions.override === 'true') {
|
|
50
|
-
ejectOptions.override = true;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const componentIds = await this.workspace.idsByPattern(pattern);
|
|
54
|
-
const results = await this.workspace.ejectMultipleConfigs(componentIds, ejectOptions as EjectConfOptions);
|
|
55
|
-
return results;
|
|
56
|
-
}
|
|
57
|
-
}
|
package/filter.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { ComponentID, ComponentIdList } from '@teambit/component-id';
|
|
2
|
-
import pMapSeries from 'p-map-series';
|
|
3
|
-
import { ModelComponent } from '@teambit/legacy/dist/scope/models';
|
|
4
|
-
import { compact } from 'lodash';
|
|
5
|
-
import { Workspace } from './workspace';
|
|
6
|
-
|
|
7
|
-
export const statesFilter = [
|
|
8
|
-
'new',
|
|
9
|
-
'modified',
|
|
10
|
-
'deprecated',
|
|
11
|
-
'deleted',
|
|
12
|
-
'snappedOnMain',
|
|
13
|
-
'softTagged',
|
|
14
|
-
'codeModified',
|
|
15
|
-
] as const;
|
|
16
|
-
export type StatesFilter = typeof statesFilter[number];
|
|
17
|
-
|
|
18
|
-
export class Filter {
|
|
19
|
-
constructor(private workspace: Workspace) {}
|
|
20
|
-
|
|
21
|
-
async by(criteria: StatesFilter | string, ids: ComponentID[]): Promise<ComponentID[]> {
|
|
22
|
-
return criteria.includes(':') ? this.byMultiParamState(criteria, ids) : this.byState(criteria as StatesFilter, ids);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async byState(state: StatesFilter, ids: ComponentID[]): Promise<ComponentID[]> {
|
|
26
|
-
const statePerMethod = {
|
|
27
|
-
new: this.byNew,
|
|
28
|
-
modified: this.byModified,
|
|
29
|
-
deprecated: this.byDeprecated,
|
|
30
|
-
deleted: this.byDeleted,
|
|
31
|
-
snappedOnMain: this.bySnappedOnMain,
|
|
32
|
-
softTagged: this.bySoftTagged,
|
|
33
|
-
codeModified: this.byCodeModified,
|
|
34
|
-
};
|
|
35
|
-
if (!statePerMethod[state]) {
|
|
36
|
-
throw new Error(`state ${state} is not recognized, possible values: ${statesFilter.join(', ')}`);
|
|
37
|
-
}
|
|
38
|
-
return statePerMethod[state].bind(this)(ids);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async byMultiParamState(state: string, ids: ComponentID[]): Promise<ComponentID[]> {
|
|
42
|
-
const stateSplit = state.split(':');
|
|
43
|
-
if (stateSplit.length < 2) {
|
|
44
|
-
throw new Error(`byMultiParamState expect the state to have at least one param after the colon, got ${state}`);
|
|
45
|
-
}
|
|
46
|
-
const [stateName, ...stateParams] = stateSplit;
|
|
47
|
-
if (stateName === 'env') {
|
|
48
|
-
return this.byEnv(stateParams[0], ids);
|
|
49
|
-
}
|
|
50
|
-
throw new Error(`byMultiParamState expect the state to be one of the following: ['env'], got ${stateName}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async byEnv(env: string, withinIds?: ComponentID[]): Promise<ComponentID[]> {
|
|
54
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
55
|
-
const comps = await this.workspace.getMany(ids);
|
|
56
|
-
const compsUsingEnv = comps.filter((c) => {
|
|
57
|
-
const envId = this.workspace.envs.getEnvId(c);
|
|
58
|
-
const envIdWithoutVer = ComponentID.getStringWithoutVersion(envId);
|
|
59
|
-
return envIdWithoutVer === env;
|
|
60
|
-
});
|
|
61
|
-
return compsUsingEnv.map((c) => c.id);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async byModified(withinIds?: ComponentID[]): Promise<ComponentID[]> {
|
|
65
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
66
|
-
const comps = await this.workspace.getMany(ids);
|
|
67
|
-
const modifiedIds = await Promise.all(comps.map(async (comp) => ((await comp.isModified()) ? comp.id : undefined)));
|
|
68
|
-
return compact(modifiedIds);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async byCodeModified(withinIds?: ComponentID[]): Promise<ComponentID[]> {
|
|
72
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
73
|
-
const compFiles = await pMapSeries(ids, (id) => this.workspace.getFilesModification(id));
|
|
74
|
-
const modifiedIds = compFiles.filter((c) => c.isModified()).map((c) => c.id);
|
|
75
|
-
return compact(modifiedIds);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async byNew(withinIds?: ComponentID[]): Promise<ComponentID[]> {
|
|
79
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
80
|
-
return ids.filter((id) => !id.hasVersion());
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async byDeprecated(withinIds?: ComponentID[]) {
|
|
84
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
85
|
-
const comps = await this.workspace.getMany(ids);
|
|
86
|
-
const results = await Promise.all(
|
|
87
|
-
comps.map(async (c) => {
|
|
88
|
-
const modelComponent = await this.workspace.consumer.scope.getModelComponentIfExist(c.id);
|
|
89
|
-
const deprecated = await modelComponent?.isDeprecated(this.workspace.consumer.scope.objects);
|
|
90
|
-
return deprecated ? c.id : null;
|
|
91
|
-
})
|
|
92
|
-
);
|
|
93
|
-
return compact(results);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async byDeleted(withinIds?: ComponentID[]) {
|
|
97
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
98
|
-
const comps = await this.workspace.getMany(ids);
|
|
99
|
-
const deletedIds = comps.filter((c) => c.isDeleted()).map((c) => c.id);
|
|
100
|
-
return compact(deletedIds);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
byDuringMergeState(): ComponentIdList {
|
|
104
|
-
const unmergedComponents = this.workspace.scope.legacyScope.objects.unmergedComponents.getComponents();
|
|
105
|
-
return ComponentIdList.fromArray(unmergedComponents.map((u) => ComponentID.fromObject(u.id)));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* list components that their head is a snap, not a tag.
|
|
110
|
-
* this is relevant only when the lane is the default (main), otherwise, the head is always a snap.
|
|
111
|
-
* components that are during-merge are filtered out, we don't want them during tag and don't want
|
|
112
|
-
* to show them in the "snapped" section in bit-status.
|
|
113
|
-
*/
|
|
114
|
-
async bySnappedOnMain(withinIds?: ComponentID[]) {
|
|
115
|
-
if (!this.workspace.isOnMain()) {
|
|
116
|
-
return [];
|
|
117
|
-
}
|
|
118
|
-
const ids = withinIds || (await this.workspace.listIds());
|
|
119
|
-
const compIds = ComponentIdList.fromArray(ids);
|
|
120
|
-
const componentsFromModel = await this.getModelComps(ids);
|
|
121
|
-
const compsDuringMerge = this.byDuringMergeState();
|
|
122
|
-
const comps = componentsFromModel
|
|
123
|
-
.filter((c) => compIds.hasWithoutVersion(c.toComponentId()))
|
|
124
|
-
.filter((c) => !compsDuringMerge.hasWithoutVersion(c.toComponentId()))
|
|
125
|
-
.filter((c) => c.isHeadSnap());
|
|
126
|
-
return comps.map((c) => c.toComponentIdWithHead());
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
bySoftTagged(withinIds?: ComponentID[]): ComponentID[] {
|
|
130
|
-
const withCompIds = ComponentIdList.fromArray(withinIds || []);
|
|
131
|
-
const all = this.workspace.consumer.bitMap.components.filter((c) => c.nextVersion).map((c) => c.id);
|
|
132
|
-
return withinIds ? all.filter((id) => withCompIds.hasWithoutVersion(id)) : all;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private async getModelComps(ids: ComponentID[]): Promise<ModelComponent[]> {
|
|
136
|
-
const comps = await Promise.all(ids.map((id) => this.workspace.scope.getBitObjectModelComponent(id, false)));
|
|
137
|
-
return compact(comps);
|
|
138
|
-
}
|
|
139
|
-
}
|
package/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { WorkspaceAspect } from './workspace.aspect';
|
|
2
|
-
// eslint-disable-next-line import/prefer-default-export
|
|
3
|
-
export type { default as Workspace, ExtensionsOrigin } from './workspace';
|
|
4
|
-
// TODO: change to module path once track the utils folder
|
|
5
|
-
export type { ResolvedComponent } from '@teambit/harmony.modules.resolved-component';
|
|
6
|
-
export type { AlreadyExistsError as ComponentConfigFileAlreadyExistsError } from './component-config-file';
|
|
7
|
-
export type { WorkspaceMain } from './workspace.main.runtime';
|
|
8
|
-
export * from './events';
|
|
9
|
-
export type { WorkspaceUI } from './workspace.ui.runtime';
|
|
10
|
-
export type { SerializableResults, OnComponentLoad, OnComponentEventResult } from './on-component-events';
|
|
11
|
-
export { ComponentStatus } from './workspace-component';
|
|
12
|
-
export type { WorkspaceModelComponent } from './ui/workspace/workspace-model';
|
|
13
|
-
export { Workspace as WorkspaceModel } from './ui/workspace/workspace-model';
|
|
14
|
-
export { WorkspaceContext } from './ui/workspace/workspace-context';
|
|
15
|
-
export { OutsideWorkspaceError } from './exceptions/outside-workspace';
|
|
16
|
-
export type { WorkspaceComponent } from './workspace-component';
|
|
17
|
-
export type { ComponentConfigFile } from './component-config-file';
|
|
18
|
-
export type { CompFiles, FilesStatus } from './workspace-component/comp-files';
|
|
19
|
-
export type { MergeOptions as BitmapMergeOptions } from './bit-map';
|
|
20
|
-
export type { WorkspaceExtConfig } from './types';
|
|
21
|
-
export { WorkspaceAspect };
|
|
22
|
-
export default WorkspaceAspect;
|
package/merge-conflict-file.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { MergeConfigFilename } from '@teambit/legacy/dist/constants';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import { MergeConfigConflict } from './exceptions/merge-config-conflict';
|
|
5
|
-
|
|
6
|
-
const idPrefix = `[*]`;
|
|
7
|
-
const idDivider = '-'.repeat(80);
|
|
8
|
-
type ConflictPerId = { [compIdWithoutVersion: string]: string };
|
|
9
|
-
|
|
10
|
-
export class MergeConflictFile {
|
|
11
|
-
conflictPerId: ConflictPerId | undefined;
|
|
12
|
-
constructor(private workspacePath: string) {}
|
|
13
|
-
|
|
14
|
-
addConflict(id: string, conflict: string) {
|
|
15
|
-
if (!this.conflictPerId) this.conflictPerId = {};
|
|
16
|
-
this.conflictPerId[id] = conflict;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
removeConflict(id: string) {
|
|
20
|
-
delete this.conflictPerId?.[id];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async getConflict(id: string): Promise<string | undefined> {
|
|
24
|
-
await this.loadIfNeeded();
|
|
25
|
-
if (!this.conflictPerId) throw new Error(`this.conflictPerId must be instantiated after load`);
|
|
26
|
-
return this.conflictPerId[id];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
getConflictAssumeIsLoaded(id: string): string | undefined {
|
|
30
|
-
if (!this.conflictPerId)
|
|
31
|
-
throw new Error(`MergeConflictFile was not loaded yet, please load it before calling this function`);
|
|
32
|
-
return this.conflictPerId[id];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
getConflictParsed(id: string): Record<string, any> | undefined {
|
|
36
|
-
const configMergeContent = this.getConflictAssumeIsLoaded(id);
|
|
37
|
-
if (!configMergeContent) return undefined;
|
|
38
|
-
try {
|
|
39
|
-
return JSON.parse(configMergeContent);
|
|
40
|
-
} catch (err: any) {
|
|
41
|
-
if (this.stringHasConflictMarker(configMergeContent)) {
|
|
42
|
-
throw new MergeConfigConflict(this.getPath());
|
|
43
|
-
}
|
|
44
|
-
throw new Error(`unable to parse the merge-conflict entry for ${id} as the JSON is invalid. err: ${err.message}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
hasConflict(): boolean {
|
|
49
|
-
return Boolean(this.conflictPerId && Object.keys(this.conflictPerId).length);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
getPath() {
|
|
53
|
-
return path.join(this.workspacePath, MergeConfigFilename);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async loadIfNeeded() {
|
|
57
|
-
if (this.conflictPerId) return; // already loaded
|
|
58
|
-
const fileContent = await this.getFileContentIfExists();
|
|
59
|
-
if (!fileContent) {
|
|
60
|
-
this.conflictPerId = {}; // to indicate that it's loaded
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const parsedConflict = this.parseConflict(fileContent);
|
|
64
|
-
this.conflictPerId = parsedConflict;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async write() {
|
|
68
|
-
if (!this.hasConflict()) return;
|
|
69
|
-
const afterFormat = this.formatConflicts();
|
|
70
|
-
await fs.writeFile(this.getPath(), afterFormat);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async delete() {
|
|
74
|
-
await fs.remove(this.getPath());
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private formatConflicts(): string {
|
|
78
|
-
const conflictPerId = this.conflictPerId;
|
|
79
|
-
if (!conflictPerId) throw new Error('conflictPerId is not populated');
|
|
80
|
-
const title = `# Resolve configuration conflicts per component and make sure the Component ID remain in place`;
|
|
81
|
-
const conflicts = Object.keys(conflictPerId)
|
|
82
|
-
.map((id) => {
|
|
83
|
-
const conflict = conflictPerId[id];
|
|
84
|
-
return `${idDivider}
|
|
85
|
-
${idPrefix} ${id}
|
|
86
|
-
${idDivider}
|
|
87
|
-
${conflict}`;
|
|
88
|
-
})
|
|
89
|
-
.join('\n\n');
|
|
90
|
-
return `${title}\n\n${conflicts}`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private stringHasConflictMarker(str: string): boolean {
|
|
94
|
-
return str.includes('<<<<<<<') || str.includes('>>>>>>>');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private parseConflict(conflict: string): ConflictPerId {
|
|
98
|
-
// remove irrelevant lines
|
|
99
|
-
conflict = conflict
|
|
100
|
-
.split('\n')
|
|
101
|
-
.filter((line) => line !== idDivider && !line.startsWith('#'))
|
|
102
|
-
.join('\n');
|
|
103
|
-
// split by id
|
|
104
|
-
const conflictPerId: ConflictPerId = {};
|
|
105
|
-
const split = conflict.split(idPrefix);
|
|
106
|
-
split.forEach((conflictItem) => {
|
|
107
|
-
const conflictItemSplit = conflictItem.split('\n');
|
|
108
|
-
const [rawId, ...conflictStr] = conflictItemSplit;
|
|
109
|
-
const id = rawId.trim();
|
|
110
|
-
if (!id) return; // first line has it empty
|
|
111
|
-
conflictPerId[id] = conflictStr.join('\n');
|
|
112
|
-
});
|
|
113
|
-
return conflictPerId;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private async getFileContentIfExists(): Promise<string | undefined> {
|
|
117
|
-
const filePath = this.getPath();
|
|
118
|
-
let fileContent: string;
|
|
119
|
-
try {
|
|
120
|
-
fileContent = await fs.readFile(filePath, 'utf-8');
|
|
121
|
-
} catch (err: any) {
|
|
122
|
-
if (err.code === 'ENOENT') {
|
|
123
|
-
return undefined;
|
|
124
|
-
}
|
|
125
|
-
throw err;
|
|
126
|
-
}
|
|
127
|
-
return fileContent;
|
|
128
|
-
}
|
|
129
|
-
}
|
package/on-component-events.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Component, ComponentID, AspectData } from '@teambit/component';
|
|
2
|
-
import { ComponentLoadOptions } from '@teambit/legacy/dist/consumer/component/component-loader';
|
|
3
|
-
import type { PathOsBasedAbsolute } from '@teambit/legacy/dist/utils/path';
|
|
4
|
-
import { WatchOptions } from '@teambit/watcher';
|
|
5
|
-
|
|
6
|
-
export type SerializableResults = { results: any; toString: () => string };
|
|
7
|
-
export type OnComponentChange = (
|
|
8
|
-
component: Component,
|
|
9
|
-
files: PathOsBasedAbsolute[],
|
|
10
|
-
removedFiles: PathOsBasedAbsolute[],
|
|
11
|
-
watchOpts: WatchOptions
|
|
12
|
-
) => Promise<SerializableResults | void>;
|
|
13
|
-
export type OnComponentAdd = (
|
|
14
|
-
component: Component,
|
|
15
|
-
files: string[],
|
|
16
|
-
watchOpts: WatchOptions
|
|
17
|
-
) => Promise<SerializableResults | void>;
|
|
18
|
-
export type OnComponentRemove = (componentId: ComponentID) => Promise<SerializableResults>;
|
|
19
|
-
export type OnComponentEventResult = { extensionId: string; results: SerializableResults };
|
|
20
|
-
|
|
21
|
-
export type OnComponentLoad = (
|
|
22
|
-
component: Component,
|
|
23
|
-
loadOpts?: ComponentLoadOptions
|
|
24
|
-
) => Promise<AspectData | undefined>;
|
package/pattern.cmd.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Command, CommandOptions } from '@teambit/cli';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { Workspace } from './workspace';
|
|
4
|
-
import { statesFilter } from './filter';
|
|
5
|
-
|
|
6
|
-
export class PatternCommand implements Command {
|
|
7
|
-
name = 'pattern <pattern>';
|
|
8
|
-
alias = '';
|
|
9
|
-
description = 'list the component ids matching the given pattern';
|
|
10
|
-
extendedDescription = `this command helps validating a pattern before using it in other commands.
|
|
11
|
-
NOTE: always wrap the pattern with quotes to avoid collision with shell commands. depending on your shell, it might be single or double quotes.
|
|
12
|
-
a pattern can be a simple component-id or component-name. e.g. 'ui/button'.
|
|
13
|
-
a pattern can be used with wildcards for multiple component ids, e.g. 'org.scope/utils/**' or '**/utils/**' to capture all org/scopes.
|
|
14
|
-
to enter multiple patterns, separate them by a comma, e.g. 'ui/*, lib/*'
|
|
15
|
-
to exclude, use '!'. e.g. 'ui/**, !ui/button'
|
|
16
|
-
the matching algorithm is from multimatch (@see https://github.com/sindresorhus/multimatch).
|
|
17
|
-
|
|
18
|
-
to filter by a state or attribute, prefix the pattern with "$". e.g. '$deprecated', '$modified'.
|
|
19
|
-
list of supported states: [${statesFilter.join(', ')}].
|
|
20
|
-
to filter by multi-params state/attribute, separate the params with ":", e.g. '$env:teambit.react/react'.
|
|
21
|
-
list of supported multi-params states: [env].
|
|
22
|
-
to match a state and another criteria, use " AND " keyword. e.g. '$modified AND teambit.workspace/**'. note that the state must be first.
|
|
23
|
-
`;
|
|
24
|
-
examples = [
|
|
25
|
-
{ cmd: "bit pattern '**'", description: 'matches all components' },
|
|
26
|
-
{
|
|
27
|
-
cmd: "bit pattern '*/ui/*'",
|
|
28
|
-
description:
|
|
29
|
-
'matches components with any scope-name and the "ui" namespace. e.g. "ui/button" but not "ui/elements/button"',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
cmd: "bit pattern '*/ui/**'",
|
|
33
|
-
description: 'matches components whose namespace starts with "ui/" e.g. "ui/button", "ui/elements/button"',
|
|
34
|
-
},
|
|
35
|
-
{ cmd: "bit pattern 'bar, foo'", description: 'matches two components: bar and foo' },
|
|
36
|
-
{ cmd: "bit pattern 'my-scope.org/**'", description: 'matches all components of the scope "my-scope.org"' },
|
|
37
|
-
];
|
|
38
|
-
group = 'development';
|
|
39
|
-
private = false;
|
|
40
|
-
options = [['j', 'json', 'return the output as JSON']] as CommandOptions;
|
|
41
|
-
|
|
42
|
-
constructor(private workspace: Workspace) {}
|
|
43
|
-
|
|
44
|
-
async report([pattern]: [string]) {
|
|
45
|
-
const ids = await this.json([pattern]);
|
|
46
|
-
const title = chalk.green(`found ${chalk.bold(ids.length.toString())} components matching the pattern`);
|
|
47
|
-
return `${title}\n${ids.join('\n')}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async json([pattern]: [string]) {
|
|
51
|
-
return this.workspace.idsByPattern(pattern, false);
|
|
52
|
-
}
|
|
53
|
-
}
|