@teambit/component-issues 0.0.170 → 0.0.171

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.
@@ -2,7 +2,7 @@ import { ComponentIssue, formatTitle } from './component-issue';
2
2
 
3
3
  export class CircularDependencies extends ComponentIssue {
4
4
  description = 'circular dependencies';
5
- solution = 'run `bit insights "circular"` to get the component-ids participating in the circular';
5
+ solution = 'run `bit deps circular` to get the component-ids participating in the circular';
6
6
  data: boolean;
7
7
  isTagBlocker = true;
8
8
  outputForCLI() {
@@ -13,7 +13,7 @@ function _componentIssue() {
13
13
  }
14
14
  class CircularDependencies extends _componentIssue().ComponentIssue {
15
15
  description = 'circular dependencies';
16
- solution = 'run `bit insights "circular"` to get the component-ids participating in the circular';
16
+ solution = 'run `bit deps circular` to get the component-ids participating in the circular';
17
17
  isTagBlocker = true;
18
18
  outputForCLI() {
19
19
  return (0, _componentIssue().formatTitle)(this.descriptionWithSolution, false);
@@ -1 +1 @@
1
- {"version":3,"names":["_componentIssue","data","require","CircularDependencies","ComponentIssue","description","solution","isTagBlocker","outputForCLI","formatTitle","descriptionWithSolution","exports"],"sources":["circular-dependencies.ts"],"sourcesContent":["import { ComponentIssue, formatTitle } from './component-issue';\n\nexport class CircularDependencies extends ComponentIssue {\n description = 'circular dependencies';\n solution = 'run `bit insights \"circular\"` to get the component-ids participating in the circular';\n data: boolean;\n isTagBlocker = true;\n outputForCLI() {\n return formatTitle(this.descriptionWithSolution, false);\n }\n}\n"],"mappings":";;;;;;AAAA,SAAAA,gBAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,eAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAEO,MAAME,oBAAoB,SAASC,gCAAc,CAAC;EACvDC,WAAW,GAAG,uBAAuB;EACrCC,QAAQ,GAAG,sFAAsF;EAEjGC,YAAY,GAAG,IAAI;EACnBC,YAAYA,CAAA,EAAG;IACb,OAAO,IAAAC,6BAAW,EAAC,IAAI,CAACC,uBAAuB,EAAE,KAAK,CAAC;EACzD;AACF;AAACC,OAAA,CAAAR,oBAAA,GAAAA,oBAAA","ignoreList":[]}
1
+ {"version":3,"names":["_componentIssue","data","require","CircularDependencies","ComponentIssue","description","solution","isTagBlocker","outputForCLI","formatTitle","descriptionWithSolution","exports"],"sources":["circular-dependencies.ts"],"sourcesContent":["import { ComponentIssue, formatTitle } from './component-issue';\n\nexport class CircularDependencies extends ComponentIssue {\n description = 'circular dependencies';\n solution = 'run `bit deps circular` to get the component-ids participating in the circular';\n data: boolean;\n isTagBlocker = true;\n outputForCLI() {\n return formatTitle(this.descriptionWithSolution, false);\n }\n}\n"],"mappings":";;;;;;AAAA,SAAAA,gBAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,eAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAEO,MAAME,oBAAoB,SAASC,gCAAc,CAAC;EACvDC,WAAW,GAAG,uBAAuB;EACrCC,QAAQ,GAAG,gFAAgF;EAE3FC,YAAY,GAAG,IAAI;EACnBC,YAAYA,CAAA,EAAG;IACb,OAAO,IAAAC,6BAAW,EAAC,IAAI,CAACC,uBAAuB,EAAE,KAAK,CAAC;EACzD;AACF;AAACC,OAAA,CAAAR,oBAAA,GAAAA,oBAAA","ignoreList":[]}
package/dist/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export { ISSUE_FORMAT_SPACE as MISSING_DEPS_SPACE, ComponentIssue } from './comp
3
3
  export { UntrackedFileDependencyEntry, MISSING_NESTED_DEPS_SPACE } from './untracked-dependencies';
4
4
  export { RelativeComponentsAuthoredEntry } from './relative-components-authored';
5
5
  export type { MissingPackagesData } from './missing-packages-dependencies-on-fs';
6
+ export { renderCycles } from './render-cycles';
package/dist/index.js CHANGED
@@ -51,6 +51,12 @@ Object.defineProperty(exports, "UntrackedFileDependencyEntry", {
51
51
  return _untrackedDependencies().UntrackedFileDependencyEntry;
52
52
  }
53
53
  });
54
+ Object.defineProperty(exports, "renderCycles", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _renderCycles().renderCycles;
58
+ }
59
+ });
54
60
  function _issuesList() {
55
61
  const data = require("./issues-list");
56
62
  _issuesList = function () {
@@ -79,5 +85,12 @@ function _relativeComponentsAuthored() {
79
85
  };
80
86
  return data;
81
87
  }
88
+ function _renderCycles() {
89
+ const data = require("./render-cycles");
90
+ _renderCycles = function () {
91
+ return data;
92
+ };
93
+ return data;
94
+ }
82
95
 
83
96
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"names":["_issuesList","data","require","_componentIssue","_untrackedDependencies","_relativeComponentsAuthored"],"sources":["index.ts"],"sourcesContent":["export { IssuesList, IssuesClasses, IssuesNames } from './issues-list';\nexport { ISSUE_FORMAT_SPACE as MISSING_DEPS_SPACE, ComponentIssue } from './component-issue';\nexport { UntrackedFileDependencyEntry, MISSING_NESTED_DEPS_SPACE } from './untracked-dependencies';\nexport { RelativeComponentsAuthoredEntry } from './relative-components-authored';\nexport type { MissingPackagesData } from './missing-packages-dependencies-on-fs';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAAA,YAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,WAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAE,gBAAA;EAAA,MAAAF,IAAA,GAAAC,OAAA;EAAAC,eAAA,YAAAA,CAAA;IAAA,OAAAF,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAG,uBAAA;EAAA,MAAAH,IAAA,GAAAC,OAAA;EAAAE,sBAAA,YAAAA,CAAA;IAAA,OAAAH,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAI,4BAAA;EAAA,MAAAJ,IAAA,GAAAC,OAAA;EAAAG,2BAAA,YAAAA,CAAA;IAAA,OAAAJ,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["_issuesList","data","require","_componentIssue","_untrackedDependencies","_relativeComponentsAuthored","_renderCycles"],"sources":["index.ts"],"sourcesContent":["export { IssuesList, IssuesClasses, IssuesNames } from './issues-list';\nexport { ISSUE_FORMAT_SPACE as MISSING_DEPS_SPACE, ComponentIssue } from './component-issue';\nexport { UntrackedFileDependencyEntry, MISSING_NESTED_DEPS_SPACE } from './untracked-dependencies';\nexport { RelativeComponentsAuthoredEntry } from './relative-components-authored';\nexport type { MissingPackagesData } from './missing-packages-dependencies-on-fs';\nexport { renderCycles } from './render-cycles';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAAA,YAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,WAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAE,gBAAA;EAAA,MAAAF,IAAA,GAAAC,OAAA;EAAAC,eAAA,YAAAA,CAAA;IAAA,OAAAF,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAG,uBAAA;EAAA,MAAAH,IAAA,GAAAC,OAAA;EAAAE,sBAAA,YAAAA,CAAA;IAAA,OAAAH,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAI,4BAAA;EAAA,MAAAJ,IAAA,GAAAC,OAAA;EAAAG,2BAAA,YAAAA,CAAA;IAAA,OAAAJ,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAEA,SAAAK,cAAA;EAAA,MAAAL,IAAA,GAAAC,OAAA;EAAAI,aAAA,YAAAA,CAAA;IAAA,OAAAL,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Render an array of cycles (each cycle is an array of component-id strings with the
3
+ * first element duplicated at the end) into a human-readable string with ASCII diagrams.
4
+ */
5
+ export declare function renderCycles(cycles: string[][]): string;
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.renderCycles = renderCycles;
7
+ function _chalk() {
8
+ const data = _interopRequireDefault(require("chalk"));
9
+ _chalk = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ const MAX_HORIZONTAL_WIDTH = 90;
16
+ const ARROW = ' ───> ';
17
+ const ARROW_LEN = 8;
18
+ function shortenNames(cycle) {
19
+ // cycle has the first element duplicated at the end; work with unique entries
20
+ const unique = cycle.slice(0, -1);
21
+
22
+ // extract scope: everything up to and including the last '/' before the component name
23
+ // e.g. "my-org.scope/ui/button@0.0.1" → scope "my-org.scope/ui", name "button", ver "0.0.1"
24
+ const parsed = unique.map(id => {
25
+ const atIdx = id.lastIndexOf('@');
26
+ const version = atIdx > 0 ? id.slice(atIdx + 1) : undefined;
27
+ const withoutVer = atIdx > 0 ? id.slice(0, atIdx) : id;
28
+ const slashIdx = withoutVer.lastIndexOf('/');
29
+ const scope = slashIdx > 0 ? withoutVer.slice(0, slashIdx) : undefined;
30
+ const name = slashIdx > 0 ? withoutVer.slice(slashIdx + 1) : withoutVer;
31
+ return {
32
+ scope,
33
+ name,
34
+ version
35
+ };
36
+ });
37
+
38
+ // common scope: only if ALL entries share the same scope
39
+ const scopes = new Set(parsed.map(p => p.scope));
40
+ const commonScope = scopes.size === 1 ? parsed[0].scope : undefined;
41
+
42
+ // common version: only if ALL entries share the same version
43
+ const versions = new Set(parsed.map(p => p.version));
44
+ const commonVersion = versions.size === 1 ? parsed[0].version : undefined;
45
+ const names = parsed.map(p => {
46
+ let display = commonScope ? p.name : p.scope ? `${p.scope}/${p.name}` : p.name;
47
+ if (!commonVersion && p.version) {
48
+ display += `@${p.version}`;
49
+ }
50
+ return display;
51
+ });
52
+ return {
53
+ names,
54
+ scope: commonScope,
55
+ version: commonVersion
56
+ };
57
+ }
58
+ function renderHeader(cycleIndex, totalCycles, componentCount, scope, version) {
59
+ const isSelf = componentCount === 1;
60
+ let header = '';
61
+ if (totalCycles > 1 && cycleIndex !== undefined) {
62
+ header += `Cycle ${cycleIndex + 1} of ${totalCycles}`;
63
+ } else {
64
+ header += 'Cycle';
65
+ }
66
+ header += isSelf ? ' - self-dependency' : ` - ${componentCount} components`;
67
+ if (scope) header += ` (scope: ${scope})`;
68
+ if (version) header += ` @${version}`;
69
+ return _chalk().default.bold(header);
70
+ }
71
+ function renderSelfCycle(name) {
72
+ return ` ${_chalk().default.cyan(name)} ⟲`;
73
+ }
74
+ function renderHorizontal(names) {
75
+ // build chain: name0 ───> name1 ───> name2
76
+ const chainParts = [];
77
+ const plainParts = [];
78
+ for (let i = 0; i < names.length; i++) {
79
+ chainParts.push(_chalk().default.cyan(names[i]));
80
+ plainParts.push(names[i]);
81
+ if (i < names.length - 1) {
82
+ chainParts.push(_chalk().default.dim(ARROW));
83
+ plainParts.push(ARROW);
84
+ }
85
+ }
86
+ const chainStr = chainParts.join('');
87
+ const plainLen = plainParts.join('').length;
88
+
89
+ // the last segment connects to the closing edge: ───┘
90
+ const closingSuffix = _chalk().default.red(' ───┘');
91
+ const closingSuffixLen = 6; // " ───┘"
92
+
93
+ const totalWidth = plainLen + closingSuffixLen;
94
+
95
+ // top bar spans from above ▼ (column 0) to the ┐ (at totalWidth - 1)
96
+ const topBar = _chalk().default.red('┌') + _chalk().default.red('─'.repeat(totalWidth - 2)) + _chalk().default.red('┐');
97
+ const sideLine = ' '.repeat(totalWidth - 1) + _chalk().default.red('│');
98
+ const entryArrow = _chalk().default.red('▼') + ' '.repeat(totalWidth - 2) + _chalk().default.red('│');
99
+ const lines = [topBar, sideLine, entryArrow, chainStr + closingSuffix];
100
+ return lines.join('\n');
101
+ }
102
+ function renderVertical(names) {
103
+ const lines = [];
104
+ for (let i = 0; i < names.length; i++) {
105
+ lines.push(_chalk().default.cyan(names[i]));
106
+ if (i < names.length - 1) {
107
+ lines.push(_chalk().default.dim(' │'));
108
+ lines.push(_chalk().default.dim(' ▼'));
109
+ }
110
+ }
111
+ // back-edge to start
112
+ lines.push(_chalk().default.red(` ╰───▶ `) + _chalk().default.cyan(names[0]) + _chalk().default.dim(' (back to start)'));
113
+ return lines.join('\n');
114
+ }
115
+
116
+ /**
117
+ * Render an array of cycles (each cycle is an array of component-id strings with the
118
+ * first element duplicated at the end) into a human-readable string with ASCII diagrams.
119
+ */
120
+ function renderCycles(cycles) {
121
+ if (!cycles.length) {
122
+ return 'No circular dependencies found';
123
+ }
124
+ const totalCycles = cycles.length;
125
+ const blocks = cycles.map((cycle, idx) => {
126
+ const componentCount = cycle.length - 1; // last entry is duplicate of first
127
+ const {
128
+ names,
129
+ scope,
130
+ version
131
+ } = shortenNames(cycle);
132
+ const cycleIndex = totalCycles > 1 ? idx : undefined;
133
+ const header = renderHeader(cycleIndex, totalCycles, componentCount, scope, version);
134
+ let body;
135
+ if (componentCount === 1) {
136
+ body = renderSelfCycle(names[0]);
137
+ } else {
138
+ const chainPlainLen = names.reduce((sum, n) => sum + n.length, 0) + (names.length - 1) * ARROW_LEN;
139
+ const horizontalWidth = chainPlainLen + 6; // + closing " ───┘"
140
+ if (horizontalWidth <= MAX_HORIZONTAL_WIDTH) {
141
+ body = renderHorizontal(names);
142
+ } else {
143
+ body = renderVertical(names);
144
+ }
145
+ }
146
+ return `${header}\n\n${body}`;
147
+ });
148
+ return '\n' + blocks.join('\n\n') + '\n';
149
+ }
150
+
151
+ //# sourceMappingURL=render-cycles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_chalk","data","_interopRequireDefault","require","e","__esModule","default","MAX_HORIZONTAL_WIDTH","ARROW","ARROW_LEN","shortenNames","cycle","unique","slice","parsed","map","id","atIdx","lastIndexOf","version","undefined","withoutVer","slashIdx","scope","name","scopes","Set","p","commonScope","size","versions","commonVersion","names","display","renderHeader","cycleIndex","totalCycles","componentCount","isSelf","header","chalk","bold","renderSelfCycle","cyan","renderHorizontal","chainParts","plainParts","i","length","push","dim","chainStr","join","plainLen","closingSuffix","red","closingSuffixLen","totalWidth","topBar","repeat","sideLine","entryArrow","lines","renderVertical","renderCycles","cycles","blocks","idx","body","chainPlainLen","reduce","sum","n","horizontalWidth"],"sources":["render-cycles.ts"],"sourcesContent":["import chalk from 'chalk';\n\nconst MAX_HORIZONTAL_WIDTH = 90;\nconst ARROW = ' ───> ';\nconst ARROW_LEN = 8;\n\ntype ShortenedInfo = {\n names: string[];\n scope: string | undefined;\n version: string | undefined;\n};\n\nfunction shortenNames(cycle: string[]): ShortenedInfo {\n // cycle has the first element duplicated at the end; work with unique entries\n const unique = cycle.slice(0, -1);\n\n // extract scope: everything up to and including the last '/' before the component name\n // e.g. \"my-org.scope/ui/button@0.0.1\" → scope \"my-org.scope/ui\", name \"button\", ver \"0.0.1\"\n const parsed = unique.map((id) => {\n const atIdx = id.lastIndexOf('@');\n const version = atIdx > 0 ? id.slice(atIdx + 1) : undefined;\n const withoutVer = atIdx > 0 ? id.slice(0, atIdx) : id;\n const slashIdx = withoutVer.lastIndexOf('/');\n const scope = slashIdx > 0 ? withoutVer.slice(0, slashIdx) : undefined;\n const name = slashIdx > 0 ? withoutVer.slice(slashIdx + 1) : withoutVer;\n return { scope, name, version };\n });\n\n // common scope: only if ALL entries share the same scope\n const scopes = new Set(parsed.map((p) => p.scope));\n const commonScope = scopes.size === 1 ? parsed[0].scope : undefined;\n\n // common version: only if ALL entries share the same version\n const versions = new Set(parsed.map((p) => p.version));\n const commonVersion = versions.size === 1 ? parsed[0].version : undefined;\n\n const names = parsed.map((p) => {\n let display = commonScope ? p.name : p.scope ? `${p.scope}/${p.name}` : p.name;\n if (!commonVersion && p.version) {\n display += `@${p.version}`;\n }\n return display;\n });\n\n return { names, scope: commonScope, version: commonVersion };\n}\n\nfunction renderHeader(\n cycleIndex: number | undefined,\n totalCycles: number,\n componentCount: number,\n scope: string | undefined,\n version: string | undefined\n): string {\n const isSelf = componentCount === 1;\n let header = '';\n\n if (totalCycles > 1 && cycleIndex !== undefined) {\n header += `Cycle ${cycleIndex + 1} of ${totalCycles}`;\n } else {\n header += 'Cycle';\n }\n\n header += isSelf ? ' - self-dependency' : ` - ${componentCount} components`;\n\n if (scope) header += ` (scope: ${scope})`;\n if (version) header += ` @${version}`;\n\n return chalk.bold(header);\n}\n\nfunction renderSelfCycle(name: string): string {\n return ` ${chalk.cyan(name)} ⟲`;\n}\n\nfunction renderHorizontal(names: string[]): string {\n // build chain: name0 ───> name1 ───> name2\n const chainParts: string[] = [];\n const plainParts: string[] = [];\n for (let i = 0; i < names.length; i++) {\n chainParts.push(chalk.cyan(names[i]));\n plainParts.push(names[i]);\n if (i < names.length - 1) {\n chainParts.push(chalk.dim(ARROW));\n plainParts.push(ARROW);\n }\n }\n\n const chainStr = chainParts.join('');\n const plainLen = plainParts.join('').length;\n\n // the last segment connects to the closing edge: ───┘\n const closingSuffix = chalk.red(' ───┘');\n const closingSuffixLen = 6; // \" ───┘\"\n\n const totalWidth = plainLen + closingSuffixLen;\n\n // top bar spans from above ▼ (column 0) to the ┐ (at totalWidth - 1)\n const topBar = chalk.red('┌') + chalk.red('─'.repeat(totalWidth - 2)) + chalk.red('┐');\n const sideLine = ' '.repeat(totalWidth - 1) + chalk.red('│');\n const entryArrow = chalk.red('▼') + ' '.repeat(totalWidth - 2) + chalk.red('│');\n\n const lines = [topBar, sideLine, entryArrow, chainStr + closingSuffix];\n return lines.join('\\n');\n}\n\nfunction renderVertical(names: string[]): string {\n const lines: string[] = [];\n for (let i = 0; i < names.length; i++) {\n lines.push(chalk.cyan(names[i]));\n if (i < names.length - 1) {\n lines.push(chalk.dim(' │'));\n lines.push(chalk.dim(' ▼'));\n }\n }\n // back-edge to start\n lines.push(chalk.red(` ╰───▶ `) + chalk.cyan(names[0]) + chalk.dim(' (back to start)'));\n return lines.join('\\n');\n}\n\n/**\n * Render an array of cycles (each cycle is an array of component-id strings with the\n * first element duplicated at the end) into a human-readable string with ASCII diagrams.\n */\nexport function renderCycles(cycles: string[][]): string {\n if (!cycles.length) {\n return 'No circular dependencies found';\n }\n const totalCycles = cycles.length;\n const blocks = cycles.map((cycle, idx) => {\n const componentCount = cycle.length - 1; // last entry is duplicate of first\n const { names, scope, version } = shortenNames(cycle);\n const cycleIndex = totalCycles > 1 ? idx : undefined;\n const header = renderHeader(cycleIndex, totalCycles, componentCount, scope, version);\n\n let body: string;\n if (componentCount === 1) {\n body = renderSelfCycle(names[0]);\n } else {\n const chainPlainLen = names.reduce((sum, n) => sum + n.length, 0) + (names.length - 1) * ARROW_LEN;\n const horizontalWidth = chainPlainLen + 6; // + closing \" ───┘\"\n if (horizontalWidth <= MAX_HORIZONTAL_WIDTH) {\n body = renderHorizontal(names);\n } else {\n body = renderVertical(names);\n }\n }\n\n return `${header}\\n\\n${body}`;\n });\n\n return '\\n' + blocks.join('\\n\\n') + '\\n';\n}\n"],"mappings":"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","ignoreList":[]}
package/index.ts CHANGED
@@ -3,3 +3,4 @@ export { ISSUE_FORMAT_SPACE as MISSING_DEPS_SPACE, ComponentIssue } from './comp
3
3
  export { UntrackedFileDependencyEntry, MISSING_NESTED_DEPS_SPACE } from './untracked-dependencies';
4
4
  export { RelativeComponentsAuthoredEntry } from './relative-components-authored';
5
5
  export type { MissingPackagesData } from './missing-packages-dependencies-on-fs';
6
+ export { renderCycles } from './render-cycles';
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@teambit/component-issues",
3
- "version": "0.0.170",
3
+ "version": "0.0.171",
4
4
  "homepage": "https://bit.cloud/teambit/component/component-issues",
5
5
  "main": "dist/index.js",
6
6
  "componentId": {
7
7
  "scope": "teambit.component",
8
8
  "name": "component-issues",
9
- "version": "0.0.170"
9
+ "version": "0.0.171"
10
10
  },
11
11
  "dependencies": {
12
12
  "chalk": "4.1.2",
@@ -0,0 +1,153 @@
1
+ import chalk from 'chalk';
2
+
3
+ const MAX_HORIZONTAL_WIDTH = 90;
4
+ const ARROW = ' ───> ';
5
+ const ARROW_LEN = 8;
6
+
7
+ type ShortenedInfo = {
8
+ names: string[];
9
+ scope: string | undefined;
10
+ version: string | undefined;
11
+ };
12
+
13
+ function shortenNames(cycle: string[]): ShortenedInfo {
14
+ // cycle has the first element duplicated at the end; work with unique entries
15
+ const unique = cycle.slice(0, -1);
16
+
17
+ // extract scope: everything up to and including the last '/' before the component name
18
+ // e.g. "my-org.scope/ui/button@0.0.1" → scope "my-org.scope/ui", name "button", ver "0.0.1"
19
+ const parsed = unique.map((id) => {
20
+ const atIdx = id.lastIndexOf('@');
21
+ const version = atIdx > 0 ? id.slice(atIdx + 1) : undefined;
22
+ const withoutVer = atIdx > 0 ? id.slice(0, atIdx) : id;
23
+ const slashIdx = withoutVer.lastIndexOf('/');
24
+ const scope = slashIdx > 0 ? withoutVer.slice(0, slashIdx) : undefined;
25
+ const name = slashIdx > 0 ? withoutVer.slice(slashIdx + 1) : withoutVer;
26
+ return { scope, name, version };
27
+ });
28
+
29
+ // common scope: only if ALL entries share the same scope
30
+ const scopes = new Set(parsed.map((p) => p.scope));
31
+ const commonScope = scopes.size === 1 ? parsed[0].scope : undefined;
32
+
33
+ // common version: only if ALL entries share the same version
34
+ const versions = new Set(parsed.map((p) => p.version));
35
+ const commonVersion = versions.size === 1 ? parsed[0].version : undefined;
36
+
37
+ const names = parsed.map((p) => {
38
+ let display = commonScope ? p.name : p.scope ? `${p.scope}/${p.name}` : p.name;
39
+ if (!commonVersion && p.version) {
40
+ display += `@${p.version}`;
41
+ }
42
+ return display;
43
+ });
44
+
45
+ return { names, scope: commonScope, version: commonVersion };
46
+ }
47
+
48
+ function renderHeader(
49
+ cycleIndex: number | undefined,
50
+ totalCycles: number,
51
+ componentCount: number,
52
+ scope: string | undefined,
53
+ version: string | undefined
54
+ ): string {
55
+ const isSelf = componentCount === 1;
56
+ let header = '';
57
+
58
+ if (totalCycles > 1 && cycleIndex !== undefined) {
59
+ header += `Cycle ${cycleIndex + 1} of ${totalCycles}`;
60
+ } else {
61
+ header += 'Cycle';
62
+ }
63
+
64
+ header += isSelf ? ' - self-dependency' : ` - ${componentCount} components`;
65
+
66
+ if (scope) header += ` (scope: ${scope})`;
67
+ if (version) header += ` @${version}`;
68
+
69
+ return chalk.bold(header);
70
+ }
71
+
72
+ function renderSelfCycle(name: string): string {
73
+ return ` ${chalk.cyan(name)} ⟲`;
74
+ }
75
+
76
+ function renderHorizontal(names: string[]): string {
77
+ // build chain: name0 ───> name1 ───> name2
78
+ const chainParts: string[] = [];
79
+ const plainParts: string[] = [];
80
+ for (let i = 0; i < names.length; i++) {
81
+ chainParts.push(chalk.cyan(names[i]));
82
+ plainParts.push(names[i]);
83
+ if (i < names.length - 1) {
84
+ chainParts.push(chalk.dim(ARROW));
85
+ plainParts.push(ARROW);
86
+ }
87
+ }
88
+
89
+ const chainStr = chainParts.join('');
90
+ const plainLen = plainParts.join('').length;
91
+
92
+ // the last segment connects to the closing edge: ───┘
93
+ const closingSuffix = chalk.red(' ───┘');
94
+ const closingSuffixLen = 6; // " ───┘"
95
+
96
+ const totalWidth = plainLen + closingSuffixLen;
97
+
98
+ // top bar spans from above ▼ (column 0) to the ┐ (at totalWidth - 1)
99
+ const topBar = chalk.red('┌') + chalk.red('─'.repeat(totalWidth - 2)) + chalk.red('┐');
100
+ const sideLine = ' '.repeat(totalWidth - 1) + chalk.red('│');
101
+ const entryArrow = chalk.red('▼') + ' '.repeat(totalWidth - 2) + chalk.red('│');
102
+
103
+ const lines = [topBar, sideLine, entryArrow, chainStr + closingSuffix];
104
+ return lines.join('\n');
105
+ }
106
+
107
+ function renderVertical(names: string[]): string {
108
+ const lines: string[] = [];
109
+ for (let i = 0; i < names.length; i++) {
110
+ lines.push(chalk.cyan(names[i]));
111
+ if (i < names.length - 1) {
112
+ lines.push(chalk.dim(' │'));
113
+ lines.push(chalk.dim(' ▼'));
114
+ }
115
+ }
116
+ // back-edge to start
117
+ lines.push(chalk.red(` ╰───▶ `) + chalk.cyan(names[0]) + chalk.dim(' (back to start)'));
118
+ return lines.join('\n');
119
+ }
120
+
121
+ /**
122
+ * Render an array of cycles (each cycle is an array of component-id strings with the
123
+ * first element duplicated at the end) into a human-readable string with ASCII diagrams.
124
+ */
125
+ export function renderCycles(cycles: string[][]): string {
126
+ if (!cycles.length) {
127
+ return 'No circular dependencies found';
128
+ }
129
+ const totalCycles = cycles.length;
130
+ const blocks = cycles.map((cycle, idx) => {
131
+ const componentCount = cycle.length - 1; // last entry is duplicate of first
132
+ const { names, scope, version } = shortenNames(cycle);
133
+ const cycleIndex = totalCycles > 1 ? idx : undefined;
134
+ const header = renderHeader(cycleIndex, totalCycles, componentCount, scope, version);
135
+
136
+ let body: string;
137
+ if (componentCount === 1) {
138
+ body = renderSelfCycle(names[0]);
139
+ } else {
140
+ const chainPlainLen = names.reduce((sum, n) => sum + n.length, 0) + (names.length - 1) * ARROW_LEN;
141
+ const horizontalWidth = chainPlainLen + 6; // + closing " ───┘"
142
+ if (horizontalWidth <= MAX_HORIZONTAL_WIDTH) {
143
+ body = renderHorizontal(names);
144
+ } else {
145
+ body = renderVertical(names);
146
+ }
147
+ }
148
+
149
+ return `${header}\n\n${body}`;
150
+ });
151
+
152
+ return '\n' + blocks.join('\n\n') + '\n';
153
+ }