@teambit/dependencies 1.0.107 → 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,335 @@
1
+ // eslint-disable-next-line max-classes-per-file
2
+ import { Command, CommandOptions } from '@teambit/cli';
3
+ import Table from 'cli-table';
4
+ import chalk from 'chalk';
5
+ import archy from 'archy';
6
+ import { generateDependenciesInfoTable } from '@teambit/legacy/dist/cli/templates/component-template';
7
+ import { IdNotFoundInGraph } from '@teambit/legacy/dist/scope/exceptions/id-not-found-in-graph';
8
+ import DependencyGraph from '@teambit/legacy/dist/scope/graph/scope-graph';
9
+ import { COMPONENT_PATTERN_HELP } from '@teambit/legacy/dist/constants';
10
+ import { DependenciesMain } from './dependencies.main.runtime';
11
+
12
+ type GetDependenciesFlags = {
13
+ tree: boolean;
14
+ };
15
+
16
+ export type SetDependenciesFlags = {
17
+ dev?: boolean;
18
+ optional?: boolean;
19
+ peer?: boolean;
20
+ };
21
+
22
+ export type RemoveDependenciesFlags = SetDependenciesFlags;
23
+
24
+ export class DependenciesGetCmd implements Command {
25
+ name = 'get <component-name>';
26
+ arguments = [{ name: 'component-name', description: 'component name or component id' }];
27
+ group = 'info';
28
+ description = 'show direct and indirect dependencies of the given component';
29
+ alias = '';
30
+ options = [['t', 'tree', 'EXPERIMENTAL. render dependencies as a tree, similar to "npm ls"']] as CommandOptions;
31
+
32
+ constructor(private deps: DependenciesMain) {}
33
+
34
+ async report([id]: [string], { tree = false }: GetDependenciesFlags) {
35
+ const results = await this.deps.getDependencies(id);
36
+
37
+ if (tree) {
38
+ const idWithVersion = results.workspaceGraph._getIdWithLatestVersion(results.id);
39
+ const getGraphAsTree = (graph: DependencyGraph) => {
40
+ try {
41
+ const graphAsTree = graph.getDependenciesAsObjectTree(idWithVersion.toString());
42
+ return archy(graphAsTree);
43
+ } catch (err: any) {
44
+ if (err.constructor.name === 'RangeError') {
45
+ return `${chalk.red(
46
+ 'unable to generate a tree representation, the graph is too big or has cyclic dependencies'
47
+ )}`;
48
+ }
49
+ throw err;
50
+ }
51
+ };
52
+ const workspaceTree = getGraphAsTree(results.workspaceGraph);
53
+ const scopeTree = getGraphAsTree(results.scopeGraph);
54
+ return `${chalk.green('workspace')}:\n${workspaceTree}\n\n${chalk.green('scope')}:\n${scopeTree}`;
55
+ }
56
+ const workspaceGraph = results.workspaceGraph.getDependenciesInfo(results.id);
57
+ const getScopeDependencies = () => {
58
+ try {
59
+ return results.scopeGraph.getDependenciesInfo(results.id);
60
+ } catch (err) {
61
+ if (err instanceof IdNotFoundInGraph) return []; // component might be new
62
+ throw err;
63
+ }
64
+ };
65
+ const scopeGraph = getScopeDependencies();
66
+ if (!scopeGraph.length && !workspaceGraph.length) {
67
+ return `no dependencies found for ${results.id.toString()}.
68
+ try running "bit cat-component ${results.id.toStringWithoutVersion()}" to see whether the component/version exists locally`;
69
+ }
70
+
71
+ const scopeTable = generateDependenciesInfoTable(scopeGraph, results.id);
72
+ const workspaceTable = generateDependenciesInfoTable(workspaceGraph, results.id);
73
+ return `${chalk.bold('Dependencies originated from workspace')}
74
+ ${workspaceTable || '<none>'}
75
+
76
+ ${chalk.bold('Dependencies originated from scope')}
77
+ ${scopeTable || '<none>'}`;
78
+ }
79
+ }
80
+
81
+ export class DependenciesDebugCmd implements Command {
82
+ name = 'debug <component-name>';
83
+ arguments = [{ name: 'component-name', description: 'component name or component id' }];
84
+ group = 'info';
85
+ description = 'show the immediate dependencies and how their versions were determined';
86
+ alias = '';
87
+ options = [] as CommandOptions;
88
+
89
+ constructor(private deps: DependenciesMain) {}
90
+
91
+ async report([id]: [string]) {
92
+ const results = await this.deps.debugDependencies(id);
93
+ return JSON.stringify(results, undefined, 4);
94
+ }
95
+ }
96
+
97
+ export class DependenciesSetCmd implements Command {
98
+ name = 'set <component-pattern> <package...>';
99
+ arguments = [
100
+ { name: 'component-pattern', description: COMPONENT_PATTERN_HELP },
101
+ {
102
+ name: 'package...',
103
+ description:
104
+ 'package name with or without a version, e.g. "lodash@1.0.0" or just "lodash" which will be resolved to the latest',
105
+ },
106
+ ];
107
+ group = 'info';
108
+ description = 'set a dependency to component(s)';
109
+ alias = '';
110
+ options = [
111
+ ['d', 'dev', 'add to the devDependencies'],
112
+ ['o', 'optional', 'add to the optionalDependencies'],
113
+ ['p', 'peer', 'add to the peerDependencies'],
114
+ ] as CommandOptions;
115
+
116
+ constructor(private deps: DependenciesMain) {}
117
+
118
+ async report([pattern, packages]: [string, string[]], setDepsFlags: SetDependenciesFlags) {
119
+ const { changedComps, addedPackages } = await this.deps.setDependency(pattern, packages, setDepsFlags);
120
+
121
+ return `${chalk.green('successfully updated dependencies')}
122
+ ${chalk.bold('changed components')}
123
+ ${changedComps.join('\n')}
124
+
125
+ ${chalk.bold('added packages')}
126
+ ${JSON.stringify(addedPackages, undefined, 4)}`;
127
+ }
128
+ }
129
+
130
+ export class DependenciesRemoveCmd implements Command {
131
+ name = 'remove <component-pattern> <package...>';
132
+ arguments = [
133
+ { name: 'component-pattern', description: COMPONENT_PATTERN_HELP },
134
+ {
135
+ name: 'package...',
136
+ description:
137
+ 'package name with or without a version, e.g. "lodash@1.0.0" or just "lodash" which will remove all lodash instances of any version',
138
+ },
139
+ ];
140
+ group = 'info';
141
+ description = 'remove a dependency to component(s)';
142
+ alias = '';
143
+ options = [
144
+ ['d', 'dev', 'remove from devDependencies'],
145
+ ['p', 'peer', 'remove from peerDependencies'],
146
+ ] as CommandOptions;
147
+
148
+ constructor(private deps: DependenciesMain) {}
149
+
150
+ async report([pattern, packages]: [string, string[]], removeDepsFlags: RemoveDependenciesFlags) {
151
+ const results = await this.deps.removeDependency(pattern, packages, removeDepsFlags);
152
+ if (!results.length) {
153
+ return chalk.yellow('the specified component-pattern do not use the entered packages. nothing to remove');
154
+ }
155
+
156
+ const output = results
157
+ .map(({ id, removedPackages }) => `${chalk.underline(id.toString())}\n${removedPackages.join('\n')}`)
158
+ .join('\n\n');
159
+
160
+ return `${chalk.green('successfully removed dependencies')}\n${output}`;
161
+ }
162
+ }
163
+
164
+ export class DependenciesUnsetCmd implements Command {
165
+ name = 'unset <component-pattern> <package...>';
166
+ arguments = [
167
+ { name: 'component-pattern', description: COMPONENT_PATTERN_HELP },
168
+ {
169
+ name: 'package...',
170
+ description:
171
+ 'package name with or without a version, e.g. "lodash@1.0.0" or just "lodash" which will remove all lodash instances of any version',
172
+ },
173
+ ];
174
+ group = 'info';
175
+ description = 'unset a dependency to component(s) that was previously set by "bit deps set"';
176
+ alias = '';
177
+ options = [
178
+ ['d', 'dev', 'unset from devDependencies'],
179
+ ['p', 'peer', 'unset from peerDependencies'],
180
+ ] as CommandOptions;
181
+
182
+ constructor(private deps: DependenciesMain) {}
183
+
184
+ async report([pattern, packages]: [string, string[]], removeDepsFlags: RemoveDependenciesFlags) {
185
+ const results = await this.deps.removeDependency(pattern, packages, removeDepsFlags, true);
186
+ if (!results.length) {
187
+ return chalk.yellow('the specified component-pattern do not use the entered packages. nothing to unset');
188
+ }
189
+
190
+ const output = results
191
+ .map(({ id, removedPackages }) => `${chalk.underline(id.toString())}\n${removedPackages.join('\n')}`)
192
+ .join('\n\n');
193
+
194
+ return `${chalk.green('successfully unset dependencies')}\n${output}`;
195
+ }
196
+ }
197
+
198
+ export class DependenciesResetCmd implements Command {
199
+ name = 'reset <component-pattern>';
200
+ arguments = [{ name: 'component-pattern', description: COMPONENT_PATTERN_HELP }];
201
+ group = 'info';
202
+ description = 'reset dependencies to the default values (revert any previously "bit deps set")';
203
+ alias = '';
204
+ options = [] as CommandOptions;
205
+
206
+ constructor(private deps: DependenciesMain) {}
207
+
208
+ async report([pattern]: [string]) {
209
+ const results = await this.deps.reset(pattern);
210
+ const comps = results.map((id) => id.toString());
211
+
212
+ return `${chalk.green('successfully reset dependencies for the following component(s)')}\n${comps}`;
213
+ }
214
+ }
215
+
216
+ export class DependenciesEjectCmd implements Command {
217
+ name = 'eject <component-pattern>';
218
+ arguments = [{ name: 'component-pattern', description: COMPONENT_PATTERN_HELP }];
219
+ group = 'info';
220
+ description = 'write dependencies that were previously set via "bit deps set" into .bitmap';
221
+ alias = '';
222
+ options = [] as CommandOptions;
223
+
224
+ constructor(private deps: DependenciesMain) {}
225
+
226
+ async report([pattern]: [string]) {
227
+ const results = await this.deps.eject(pattern);
228
+ const comps = results.map((id) => id.toString());
229
+
230
+ return `${chalk.green('successfully ejected dependencies for the following component(s)')}\n${comps}`;
231
+ }
232
+ }
233
+
234
+ export class DependenciesBlameCmd implements Command {
235
+ name = 'blame <component-name> <dependency-name>';
236
+ arguments = [
237
+ {
238
+ name: 'dependency-name',
239
+ description: 'package-name. for components, you can use either component-id or package-name',
240
+ },
241
+ ];
242
+ group = 'info';
243
+ description = 'EXPERIMENTAL. find out which snap/tag changed a dependency version';
244
+ alias = '';
245
+ options = [] as CommandOptions;
246
+
247
+ constructor(private deps: DependenciesMain) {}
248
+
249
+ async report([compName, depName]: [string, string]) {
250
+ const results = await this.deps.blame(compName, depName);
251
+ if (!results.length) {
252
+ return chalk.yellow(`the specified component ${compName} does not use the entered dependency ${depName}`);
253
+ }
254
+ // table with no style and no borders, just to align the columns.
255
+ const table = new Table({
256
+ chars: {
257
+ top: '',
258
+ 'top-mid': '',
259
+ 'top-left': '',
260
+ 'top-right': '',
261
+ bottom: '',
262
+ 'bottom-mid': '',
263
+ 'bottom-left': '',
264
+ 'bottom-right': '',
265
+ left: '',
266
+ 'left-mid': '',
267
+ mid: '',
268
+ 'mid-mid': '',
269
+ right: '',
270
+ 'right-mid': '',
271
+ middle: ' ',
272
+ },
273
+ style: { 'padding-left': 0, 'padding-right': 0 },
274
+ });
275
+
276
+ results.map(({ snap, tag, author, date, message, version }) =>
277
+ table.push([snap, tag || '', author, date, message, version])
278
+ );
279
+
280
+ return table.toString();
281
+ }
282
+ }
283
+
284
+ type DependenciesUsageCmdOptions = {
285
+ depth?: number;
286
+ };
287
+
288
+ export class DependenciesUsageCmd implements Command {
289
+ name = 'usage <dependency-name>';
290
+ arguments = [
291
+ {
292
+ name: 'dependency-name',
293
+ description:
294
+ 'package-name. for components, you can use either component-id or package-name. if version is specified, it will search for the exact version',
295
+ },
296
+ ];
297
+ group = 'info';
298
+ description = 'EXPERIMENTAL. find components that use the specified dependency';
299
+ alias = '';
300
+ options = [['', 'depth <number>', 'max display depth of the dependency graph']] as CommandOptions;
301
+
302
+ constructor(private deps: DependenciesMain) {}
303
+
304
+ async report([depName]: [string], options: DependenciesUsageCmdOptions) {
305
+ const deepUsageResult = await this.deps.usageDeep(depName, options);
306
+ if (deepUsageResult != null) return deepUsageResult;
307
+ const results = await this.deps.usage(depName);
308
+ if (!Object.keys(results).length) {
309
+ return chalk.yellow(`the specified dependency ${depName} is not used by any component`);
310
+ }
311
+ return Object.keys(results)
312
+ .map((compIdStr) => `${chalk.bold(compIdStr)} (using dep in version ${results[compIdStr]})`)
313
+ .join('\n');
314
+ }
315
+ }
316
+
317
+ export class WhyCmd extends DependenciesUsageCmd {
318
+ name = 'why <dependency-name>';
319
+ }
320
+
321
+ export class DependenciesCmd implements Command {
322
+ name = 'deps <sub-command>';
323
+ alias = 'dependencies';
324
+ description = 'manage dependencies';
325
+ options = [];
326
+ group = 'info';
327
+ commands: Command[] = [];
328
+ helpUrl = 'reference/dependencies/configuring-dependencies';
329
+
330
+ async report([unrecognizedSubcommand]: [string]) {
331
+ return chalk.red(
332
+ `"${unrecognizedSubcommand}" is not a subcommand of "dependencies", please run "bit dependencies --help" to list the subcommands`
333
+ );
334
+ }
335
+ }
@@ -0,0 +1,5 @@
1
+ import { Aspect } from '@teambit/harmony';
2
+
3
+ export const DependenciesAspect = Aspect.create({
4
+ id: 'teambit.dependencies/dependencies',
5
+ });