@blotch/dolan 0.0.0-stage → 22.2.0

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.
Files changed (273) hide show
  1. package/dist/commands/add.d.ts +22 -0
  2. package/dist/commands/add.js +132 -0
  3. package/dist/commands/add.js.map +1 -0
  4. package/dist/commands/add.test.d.ts +1 -0
  5. package/dist/commands/add.test.js +209 -0
  6. package/dist/commands/add.test.js.map +1 -0
  7. package/dist/commands/diff.d.ts +13 -0
  8. package/dist/commands/diff.js +155 -0
  9. package/dist/commands/diff.js.map +1 -0
  10. package/dist/commands/diff.test.d.ts +1 -0
  11. package/dist/commands/diff.test.js +327 -0
  12. package/dist/commands/diff.test.js.map +1 -0
  13. package/dist/commands/doctor.d.ts +15 -0
  14. package/dist/commands/doctor.js +248 -0
  15. package/dist/commands/doctor.js.map +1 -0
  16. package/dist/commands/doctor.test.d.ts +1 -0
  17. package/dist/commands/doctor.test.js +301 -0
  18. package/dist/commands/doctor.test.js.map +1 -0
  19. package/dist/commands/eject.d.ts +11 -0
  20. package/dist/commands/eject.js +55 -0
  21. package/dist/commands/eject.js.map +1 -0
  22. package/dist/commands/eject.test.d.ts +1 -0
  23. package/dist/commands/eject.test.js +151 -0
  24. package/dist/commands/eject.test.js.map +1 -0
  25. package/dist/commands/info.d.ts +1 -0
  26. package/dist/commands/info.js +73 -0
  27. package/dist/commands/info.js.map +1 -0
  28. package/dist/commands/info.test.d.ts +1 -0
  29. package/dist/commands/info.test.js +143 -0
  30. package/dist/commands/info.test.js.map +1 -0
  31. package/dist/commands/init.d.ts +1 -0
  32. package/dist/commands/init.js +98 -0
  33. package/dist/commands/init.js.map +1 -0
  34. package/dist/commands/init.test.d.ts +1 -0
  35. package/dist/commands/init.test.js +154 -0
  36. package/dist/commands/init.test.js.map +1 -0
  37. package/dist/commands/list.d.ts +16 -0
  38. package/dist/commands/list.js +124 -0
  39. package/dist/commands/list.js.map +1 -0
  40. package/dist/commands/list.test.d.ts +1 -0
  41. package/dist/commands/list.test.js +285 -0
  42. package/dist/commands/list.test.js.map +1 -0
  43. package/dist/commands/outdated.d.ts +13 -0
  44. package/dist/commands/outdated.js +116 -0
  45. package/dist/commands/outdated.js.map +1 -0
  46. package/dist/commands/outdated.test.d.ts +1 -0
  47. package/dist/commands/outdated.test.js +208 -0
  48. package/dist/commands/outdated.test.js.map +1 -0
  49. package/dist/commands/remove.d.ts +18 -0
  50. package/dist/commands/remove.js +161 -0
  51. package/dist/commands/remove.js.map +1 -0
  52. package/dist/commands/remove.test.d.ts +1 -0
  53. package/dist/commands/remove.test.js +361 -0
  54. package/dist/commands/remove.test.js.map +1 -0
  55. package/dist/commands/theme.d.ts +1 -0
  56. package/dist/commands/theme.js +66 -0
  57. package/dist/commands/theme.js.map +1 -0
  58. package/dist/commands/theme.test.d.ts +1 -0
  59. package/dist/commands/theme.test.js +133 -0
  60. package/dist/commands/theme.test.js.map +1 -0
  61. package/dist/commands/update.d.ts +31 -0
  62. package/dist/commands/update.js +601 -0
  63. package/dist/commands/update.js.map +1 -0
  64. package/dist/commands/update.test.d.ts +1 -0
  65. package/dist/commands/update.test.js +1233 -0
  66. package/dist/commands/update.test.js.map +1 -0
  67. package/dist/config.d.ts +11 -0
  68. package/dist/config.js +19 -0
  69. package/dist/config.js.map +1 -0
  70. package/dist/config.test.d.ts +1 -0
  71. package/dist/config.test.js +48 -0
  72. package/dist/config.test.js.map +1 -0
  73. package/dist/index.d.ts +2 -0
  74. package/dist/index.js +89 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/lockfile.d.ts +21 -0
  77. package/dist/lockfile.js +39 -0
  78. package/dist/lockfile.js.map +1 -0
  79. package/dist/registry.d.ts +14 -0
  80. package/dist/registry.js +85 -0
  81. package/dist/registry.js.map +1 -0
  82. package/dist/registry.test.d.ts +1 -0
  83. package/dist/registry.test.js +95 -0
  84. package/dist/registry.test.js.map +1 -0
  85. package/dist/test-utils.d.ts +16 -0
  86. package/dist/test-utils.js +65 -0
  87. package/dist/test-utils.js.map +1 -0
  88. package/dist/ui/components/accordion/accordion.test.ts +194 -0
  89. package/dist/ui/components/accordion/accordion.ts +173 -0
  90. package/dist/ui/components/accordion/index.ts +6 -0
  91. package/dist/ui/components/action-sheet/action-sheet.test.ts +211 -0
  92. package/dist/ui/components/action-sheet/action-sheet.ts +353 -0
  93. package/dist/ui/components/action-sheet/index.ts +6 -0
  94. package/dist/ui/components/alert/alert.test.ts +48 -0
  95. package/dist/ui/components/alert/alert.ts +104 -0
  96. package/dist/ui/components/alert/index.ts +1 -0
  97. package/dist/ui/components/alert-dialog/alert-dialog.test.ts +141 -0
  98. package/dist/ui/components/alert-dialog/alert-dialog.ts +243 -0
  99. package/dist/ui/components/alert-dialog/index.ts +7 -0
  100. package/dist/ui/components/area-chart/area-chart-render.test.ts +121 -0
  101. package/dist/ui/components/area-chart/area-chart.test.ts +158 -0
  102. package/dist/ui/components/area-chart/area-chart.ts +349 -0
  103. package/dist/ui/components/area-chart/index.ts +6 -0
  104. package/dist/ui/components/aspect-ratio/aspect-ratio.test.ts +10 -0
  105. package/dist/ui/components/aspect-ratio/aspect-ratio.ts +28 -0
  106. package/dist/ui/components/aspect-ratio/index.ts +1 -0
  107. package/dist/ui/components/avatar/avatar.test.ts +69 -0
  108. package/dist/ui/components/avatar/avatar.ts +131 -0
  109. package/dist/ui/components/avatar/index.ts +1 -0
  110. package/dist/ui/components/badge/badge.test.ts +49 -0
  111. package/dist/ui/components/badge/badge.ts +97 -0
  112. package/dist/ui/components/badge/index.ts +1 -0
  113. package/dist/ui/components/bar-chart/bar-chart-render.test.ts +174 -0
  114. package/dist/ui/components/bar-chart/bar-chart.test.ts +73 -0
  115. package/dist/ui/components/bar-chart/bar-chart.ts +327 -0
  116. package/dist/ui/components/bar-chart/index.ts +6 -0
  117. package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +163 -0
  118. package/dist/ui/components/bottom-sheet/bottom-sheet.ts +339 -0
  119. package/dist/ui/components/bottom-sheet/index.ts +1 -0
  120. package/dist/ui/components/button/button-render.test.ts +113 -0
  121. package/dist/ui/components/button/button.test.ts +70 -0
  122. package/dist/ui/components/button/button.ts +170 -0
  123. package/dist/ui/components/button/index.ts +6 -0
  124. package/dist/ui/components/button-group/button-group-render.test.ts +146 -0
  125. package/dist/ui/components/button-group/button-group.test.ts +54 -0
  126. package/dist/ui/components/button-group/button-group.ts +209 -0
  127. package/dist/ui/components/button-group/index.ts +8 -0
  128. package/dist/ui/components/candlestick-chart/candlestick-chart-render.test.ts +174 -0
  129. package/dist/ui/components/candlestick-chart/candlestick-chart.test.ts +96 -0
  130. package/dist/ui/components/candlestick-chart/candlestick-chart.ts +355 -0
  131. package/dist/ui/components/candlestick-chart/index.ts +7 -0
  132. package/dist/ui/components/card/card.test.ts +110 -0
  133. package/dist/ui/components/card/card.ts +162 -0
  134. package/dist/ui/components/card/index.ts +8 -0
  135. package/dist/ui/components/cartesian-chart/cartesian-chart-render.test.ts +188 -0
  136. package/dist/ui/components/cartesian-chart/cartesian-chart.test.ts +549 -0
  137. package/dist/ui/components/cartesian-chart/cartesian-chart.ts +1140 -0
  138. package/dist/ui/components/cartesian-chart/index.ts +18 -0
  139. package/dist/ui/components/checkbox/checkbox.test.ts +59 -0
  140. package/dist/ui/components/checkbox/checkbox.ts +96 -0
  141. package/dist/ui/components/checkbox/index.ts +1 -0
  142. package/dist/ui/components/collapsible/collapsible.test.ts +112 -0
  143. package/dist/ui/components/collapsible/collapsible.ts +122 -0
  144. package/dist/ui/components/collapsible/index.ts +5 -0
  145. package/dist/ui/components/dialog/dialog.test.ts +157 -0
  146. package/dist/ui/components/dialog/dialog.ts +248 -0
  147. package/dist/ui/components/dialog/index.ts +7 -0
  148. package/dist/ui/components/empty-state/empty-state.test.ts +60 -0
  149. package/dist/ui/components/empty-state/empty-state.ts +46 -0
  150. package/dist/ui/components/empty-state/index.ts +1 -0
  151. package/dist/ui/components/icon/icon.test.ts +52 -0
  152. package/dist/ui/components/icon/icon.ts +54 -0
  153. package/dist/ui/components/icon/icons.ts +569 -0
  154. package/dist/ui/components/icon/index.ts +2 -0
  155. package/dist/ui/components/input/index.ts +1 -0
  156. package/dist/ui/components/input/input.test.ts +134 -0
  157. package/dist/ui/components/input/input.ts +189 -0
  158. package/dist/ui/components/label/index.ts +1 -0
  159. package/dist/ui/components/label/label.test.ts +38 -0
  160. package/dist/ui/components/label/label.ts +24 -0
  161. package/dist/ui/components/line-chart/index.ts +6 -0
  162. package/dist/ui/components/line-chart/line-chart-render.test.ts +121 -0
  163. package/dist/ui/components/line-chart/line-chart.test.ts +81 -0
  164. package/dist/ui/components/line-chart/line-chart.ts +273 -0
  165. package/dist/ui/components/list/index.ts +1 -0
  166. package/dist/ui/components/list/list.test.ts +35 -0
  167. package/dist/ui/components/list/list.ts +71 -0
  168. package/dist/ui/components/nav-drawer/index.ts +8 -0
  169. package/dist/ui/components/nav-drawer/nav-drawer.test.ts +267 -0
  170. package/dist/ui/components/nav-drawer/nav-drawer.ts +504 -0
  171. package/dist/ui/components/pagination/index.ts +1 -0
  172. package/dist/ui/components/pagination/pagination.test.ts +96 -0
  173. package/dist/ui/components/pagination/pagination.ts +147 -0
  174. package/dist/ui/components/progress/index.ts +1 -0
  175. package/dist/ui/components/progress/progress.test.ts +71 -0
  176. package/dist/ui/components/progress/progress.ts +118 -0
  177. package/dist/ui/components/radio-group/index.ts +1 -0
  178. package/dist/ui/components/radio-group/radio-group.test.ts +115 -0
  179. package/dist/ui/components/radio-group/radio-group.ts +129 -0
  180. package/dist/ui/components/scatter-chart/index.ts +6 -0
  181. package/dist/ui/components/scatter-chart/scatter-chart-render.test.ts +157 -0
  182. package/dist/ui/components/scatter-chart/scatter-chart.test.ts +57 -0
  183. package/dist/ui/components/scatter-chart/scatter-chart.ts +277 -0
  184. package/dist/ui/components/scroll-area/index.ts +1 -0
  185. package/dist/ui/components/scroll-area/scroll-area.test.ts +40 -0
  186. package/dist/ui/components/scroll-area/scroll-area.ts +73 -0
  187. package/dist/ui/components/select/index.ts +1 -0
  188. package/dist/ui/components/select/select.test.ts +107 -0
  189. package/dist/ui/components/select/select.ts +146 -0
  190. package/dist/ui/components/separator/index.ts +1 -0
  191. package/dist/ui/components/separator/separator.test.ts +26 -0
  192. package/dist/ui/components/separator/separator.ts +45 -0
  193. package/dist/ui/components/sheet/index.ts +7 -0
  194. package/dist/ui/components/sheet/sheet.test.ts +44 -0
  195. package/dist/ui/components/sheet/sheet.ts +114 -0
  196. package/dist/ui/components/skeleton/index.ts +1 -0
  197. package/dist/ui/components/skeleton/skeleton.test.ts +13 -0
  198. package/dist/ui/components/skeleton/skeleton.ts +45 -0
  199. package/dist/ui/components/spinner/index.ts +1 -0
  200. package/dist/ui/components/spinner/spinner.test.ts +39 -0
  201. package/dist/ui/components/spinner/spinner.ts +83 -0
  202. package/dist/ui/components/switch/index.ts +1 -0
  203. package/dist/ui/components/switch/switch.test.ts +63 -0
  204. package/dist/ui/components/switch/switch.ts +98 -0
  205. package/dist/ui/components/tabs/index.ts +1 -0
  206. package/dist/ui/components/tabs/tabs.test.ts +199 -0
  207. package/dist/ui/components/tabs/tabs.ts +317 -0
  208. package/dist/ui/components/textarea/index.ts +1 -0
  209. package/dist/ui/components/textarea/textarea.test.ts +138 -0
  210. package/dist/ui/components/textarea/textarea.ts +221 -0
  211. package/dist/ui/components/toast/index.ts +9 -0
  212. package/dist/ui/components/toast/toast-state.test.ts +54 -0
  213. package/dist/ui/components/toast/toast-state.ts +46 -0
  214. package/dist/ui/components/toast/toast.test.ts +342 -0
  215. package/dist/ui/components/toast/toast.ts +527 -0
  216. package/dist/ui/components/toggle/index.ts +7 -0
  217. package/dist/ui/components/toggle/toggle.test.ts +186 -0
  218. package/dist/ui/components/toggle/toggle.ts +218 -0
  219. package/dist/ui/components/typography/index.ts +5 -0
  220. package/dist/ui/components/typography/typography.test.ts +55 -0
  221. package/dist/ui/components/typography/typography.ts +44 -0
  222. package/dist/ui/theme/dark.css +41 -0
  223. package/dist/ui/theme/default.css +56 -0
  224. package/dist/ui/theme/tailwind-plugin.test.ts +124 -0
  225. package/dist/ui/theme/tailwind-plugin.ts +151 -0
  226. package/dist/ui/utils/animate.test.ts +324 -0
  227. package/dist/ui/utils/animate.ts +544 -0
  228. package/dist/ui/utils/cn.test.ts +27 -0
  229. package/dist/ui/utils/cn.ts +6 -0
  230. package/dist/utils/analyze.d.ts +32 -0
  231. package/dist/utils/analyze.js +109 -0
  232. package/dist/utils/analyze.js.map +1 -0
  233. package/dist/utils/analyze.test.d.ts +1 -0
  234. package/dist/utils/analyze.test.js +146 -0
  235. package/dist/utils/analyze.test.js.map +1 -0
  236. package/dist/utils/animate.d.ts +210 -0
  237. package/dist/utils/animate.js +423 -0
  238. package/dist/utils/animate.js.map +1 -0
  239. package/dist/utils/animate.test.d.ts +1 -0
  240. package/dist/utils/animate.test.js +365 -0
  241. package/dist/utils/animate.test.js.map +1 -0
  242. package/dist/utils/banner.d.ts +1 -0
  243. package/dist/utils/banner.js +15 -0
  244. package/dist/utils/banner.js.map +1 -0
  245. package/dist/utils/banner.test.d.ts +1 -0
  246. package/dist/utils/banner.test.js +29 -0
  247. package/dist/utils/banner.test.js.map +1 -0
  248. package/dist/utils/cn.d.ts +2 -0
  249. package/dist/utils/cn.js +6 -0
  250. package/dist/utils/cn.js.map +1 -0
  251. package/dist/utils/cn.test.d.ts +1 -0
  252. package/dist/utils/cn.test.js +21 -0
  253. package/dist/utils/cn.test.js.map +1 -0
  254. package/dist/utils/format.d.ts +31 -0
  255. package/dist/utils/format.js +95 -0
  256. package/dist/utils/format.js.map +1 -0
  257. package/dist/utils/format.test.d.ts +1 -0
  258. package/dist/utils/format.test.js +71 -0
  259. package/dist/utils/format.test.js.map +1 -0
  260. package/dist/utils/logger.d.ts +6 -0
  261. package/dist/utils/logger.js +16 -0
  262. package/dist/utils/logger.js.map +1 -0
  263. package/dist/utils/logger.test.d.ts +1 -0
  264. package/dist/utils/logger.test.js +36 -0
  265. package/dist/utils/logger.test.js.map +1 -0
  266. package/dist/utils/resolve-paths.d.ts +12 -0
  267. package/dist/utils/resolve-paths.js +29 -0
  268. package/dist/utils/resolve-paths.js.map +1 -0
  269. package/dist/utils/resolve-paths.test.d.ts +1 -0
  270. package/dist/utils/resolve-paths.test.js +52 -0
  271. package/dist/utils/resolve-paths.test.js.map +1 -0
  272. package/package.json +56 -4
  273. package/README.md +0 -3
@@ -0,0 +1,208 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { join } from 'node:path';
3
+ import { readdirSync } from 'node:fs';
4
+ import { createFixture, DEFAULT_CONFIG } from '../test-utils';
5
+ import { hashContent } from '../lockfile';
6
+ vi.mock('@clack/prompts', () => ({
7
+ intro: vi.fn(),
8
+ outro: vi.fn(),
9
+ log: {
10
+ message: vi.fn(),
11
+ error: vi.fn(),
12
+ warn: vi.fn(),
13
+ success: vi.fn(),
14
+ info: vi.fn(),
15
+ },
16
+ }));
17
+ let fixture;
18
+ let consoleSpy;
19
+ vi.mock('../utils/resolve-paths.js', () => ({
20
+ getUiSourceDir: () => fixture.uiDir,
21
+ getComponentSourceDir: (name) => join(fixture.uiDir, 'components', name),
22
+ getComponentFiles: (name) => readdirSync(join(fixture.uiDir, 'components', name)).filter((f) => f.endsWith('.ts')),
23
+ rewriteImports: (content) => content,
24
+ }));
25
+ beforeEach(() => {
26
+ vi.spyOn(process, 'exit').mockImplementation((code) => {
27
+ throw new Error(`process.exit(${code})`);
28
+ });
29
+ consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
30
+ });
31
+ afterEach(() => {
32
+ fixture?.cleanup();
33
+ vi.restoreAllMocks();
34
+ });
35
+ describe('outdatedCommand', () => {
36
+ it('shows nothing when all components are up-to-date', async () => {
37
+ const content = 'export const Card = {};';
38
+ fixture = createFixture({
39
+ config: DEFAULT_CONFIG,
40
+ lockfile: {
41
+ version: 1,
42
+ components: { card: { 'card.ts': { hash: hashContent(content) } } },
43
+ utils: {},
44
+ theme: {},
45
+ },
46
+ components: { card: { 'card.ts': content } },
47
+ uiSource: { card: { 'card.ts': content } },
48
+ });
49
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
50
+ const p = await import('@clack/prompts');
51
+ const { outdatedCommand } = await import('./outdated');
52
+ await outdatedCommand({});
53
+ expect(p.log.success).toHaveBeenCalled();
54
+ });
55
+ it('lists outdated components in JSON mode and exits with code 1', async () => {
56
+ const installed = 'export const Card = {};';
57
+ const upstream = 'export const Card = { v2: true };';
58
+ fixture = createFixture({
59
+ config: DEFAULT_CONFIG,
60
+ lockfile: {
61
+ version: 1,
62
+ components: { card: { 'card.ts': { hash: hashContent(installed) } } },
63
+ utils: {},
64
+ theme: {},
65
+ },
66
+ components: { card: { 'card.ts': installed } },
67
+ uiSource: { card: { 'card.ts': upstream } },
68
+ });
69
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
70
+ const { outdatedCommand } = await import('./outdated');
71
+ await expect(outdatedCommand({ json: true })).rejects.toThrow('process.exit(1)');
72
+ const output = JSON.parse(consoleSpy.mock.calls[0][0]);
73
+ expect(output.components).toHaveLength(1);
74
+ expect(output.components[0].name).toBe('card');
75
+ expect(output.components[0].status).toBe('auto-update');
76
+ });
77
+ it('exits with error (json) when no config exists', async () => {
78
+ fixture = createFixture({});
79
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
80
+ const { outdatedCommand } = await import('./outdated');
81
+ await expect(outdatedCommand({ json: true })).rejects.toThrow('process.exit(1)');
82
+ const output = JSON.parse(consoleSpy.mock.calls[0][0]);
83
+ expect(output.error).toBe('no config found');
84
+ });
85
+ it('exits with error (non-json) when no config exists', async () => {
86
+ fixture = createFixture({});
87
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
88
+ const p = await import('@clack/prompts');
89
+ const { outdatedCommand } = await import('./outdated');
90
+ await expect(outdatedCommand({})).rejects.toThrow('process.exit(1)');
91
+ expect(p.intro).toHaveBeenCalled();
92
+ expect(p.log.error).toHaveBeenCalledWith(expect.stringContaining('dolan.config.json'));
93
+ });
94
+ it('returns empty JSON when the components directory does not exist', async () => {
95
+ fixture = createFixture({ config: DEFAULT_CONFIG, uiSource: {} });
96
+ const { rmSync } = await import('node:fs');
97
+ rmSync(join(fixture.dir, DEFAULT_CONFIG.aliases.components), {
98
+ recursive: true,
99
+ force: true,
100
+ });
101
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
102
+ const { outdatedCommand } = await import('./outdated');
103
+ await outdatedCommand({ json: true });
104
+ const output = JSON.parse(consoleSpy.mock.calls[0][0]);
105
+ expect(output.components).toHaveLength(0);
106
+ });
107
+ it('reports success (non-json) when the components directory does not exist', async () => {
108
+ fixture = createFixture({ config: DEFAULT_CONFIG, uiSource: {} });
109
+ const { rmSync } = await import('node:fs');
110
+ rmSync(join(fixture.dir, DEFAULT_CONFIG.aliases.components), {
111
+ recursive: true,
112
+ force: true,
113
+ });
114
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
115
+ const p = await import('@clack/prompts');
116
+ const { outdatedCommand } = await import('./outdated');
117
+ await outdatedCommand({});
118
+ expect(p.log.success).toHaveBeenCalledWith(expect.stringContaining('No components installed'));
119
+ });
120
+ it('returns empty JSON when nothing installed is recognized', async () => {
121
+ fixture = createFixture({ config: DEFAULT_CONFIG, uiSource: {} });
122
+ // components dir exists (via createFixture) but empty
123
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
124
+ const { outdatedCommand } = await import('./outdated');
125
+ await outdatedCommand({ json: true });
126
+ const output = JSON.parse(consoleSpy.mock.calls[0][0]);
127
+ expect(output.components).toHaveLength(0);
128
+ });
129
+ it('reports success (non-json) when nothing installed is recognized', async () => {
130
+ fixture = createFixture({ config: DEFAULT_CONFIG, uiSource: {} });
131
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
132
+ const p = await import('@clack/prompts');
133
+ const { outdatedCommand } = await import('./outdated');
134
+ await outdatedCommand({});
135
+ expect(p.log.success).toHaveBeenCalledWith(expect.stringContaining('No components installed'));
136
+ });
137
+ it('prints the non-json outdated listing and exits 1', async () => {
138
+ const installed = 'export const Card = { v: 1 };';
139
+ const upstream = 'export const Card = { v: 2 };';
140
+ fixture = createFixture({
141
+ config: DEFAULT_CONFIG,
142
+ lockfile: {
143
+ version: 1,
144
+ components: { card: { 'card.ts': { hash: hashContent(installed) } } },
145
+ utils: {},
146
+ theme: {},
147
+ },
148
+ components: { card: { 'card.ts': installed } },
149
+ uiSource: { card: { 'card.ts': upstream } },
150
+ });
151
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
152
+ const p = await import('@clack/prompts');
153
+ const { outdatedCommand } = await import('./outdated');
154
+ await expect(outdatedCommand({})).rejects.toThrow('process.exit(1)');
155
+ const messages = p.log.message.mock.calls
156
+ .map((c) => c[0])
157
+ .join('\n');
158
+ expect(messages).toContain('card');
159
+ const outroCalls = p.outro.mock.calls;
160
+ const outroArg = outroCalls[outroCalls.length - 1][0];
161
+ expect(outroArg).toContain('component(s) need attention');
162
+ });
163
+ it('handles a multi-file outdated component with no lockfile entry at all', async () => {
164
+ // lockfile.components['card'] is entirely absent (exercises the
165
+ // `lockfile.components[name] ?? {}` fallback) and one file is missing on
166
+ // disk (new-upstream, exercises the `currentContent === null` path).
167
+ // Two files also exercises the plural "N files" label in the listing.
168
+ const mainContent = 'export const Card = {};';
169
+ const newFileContent = 'export const CardNew = {};';
170
+ fixture = createFixture({
171
+ config: DEFAULT_CONFIG,
172
+ lockfile: { version: 1, components: {}, utils: {}, theme: {} },
173
+ components: { card: { 'card.ts': mainContent } },
174
+ uiSource: {
175
+ card: { 'card.ts': mainContent, 'card-new.ts': newFileContent },
176
+ },
177
+ });
178
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
179
+ const p = await import('@clack/prompts');
180
+ const { outdatedCommand } = await import('./outdated');
181
+ await expect(outdatedCommand({})).rejects.toThrow('process.exit(1)');
182
+ const messages = p.log.message.mock.calls
183
+ .map((c) => c[0])
184
+ .join('\n');
185
+ expect(messages).toContain('2 files');
186
+ });
187
+ it('returns empty JSON when all up-to-date and exits 0', async () => {
188
+ const content = 'export const Card = {};';
189
+ fixture = createFixture({
190
+ config: DEFAULT_CONFIG,
191
+ lockfile: {
192
+ version: 1,
193
+ components: { card: { 'card.ts': { hash: hashContent(content) } } },
194
+ utils: {},
195
+ theme: {},
196
+ },
197
+ components: { card: { 'card.ts': content } },
198
+ uiSource: { card: { 'card.ts': content } },
199
+ });
200
+ vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
201
+ const { outdatedCommand } = await import('./outdated');
202
+ // exit(0) is called — but since our mock throws, catch it
203
+ await expect(outdatedCommand({ json: true })).rejects.toThrow('process.exit(0)');
204
+ const output = JSON.parse(consoleSpy.mock.calls[0][0]);
205
+ expect(output.components).toHaveLength(0);
206
+ });
207
+ });
208
+ //# sourceMappingURL=outdated.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outdated.test.js","sourceRoot":"","sources":["../../src/commands/outdated.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Removes one installed UI component from the user's project, and offers to
3
+ * also remove any dependencies that would become orphaned (installed but no
4
+ * longer referenced by any remaining installed component).
5
+ *
6
+ * Two safety nets:
7
+ * - **Dependents check** — if other installed components still depend on
8
+ * this one, warn before removal because removing it would break them.
9
+ * - **Orphan detection** — `findOrphans` walks the registry to find
10
+ * dependencies that became "dead weight" after this removal. The user
11
+ * opts in via prompt (default yes — cleanup is usually what they want).
12
+ *
13
+ * `--force` skips both prompts: dependents are removed anyway, and orphans
14
+ * are auto-removed without asking.
15
+ */
16
+ export declare const removeCommand: (component: string, options: {
17
+ force?: boolean;
18
+ }) => Promise<void>;
@@ -0,0 +1,161 @@
1
+ import * as p from '@clack/prompts';
2
+ import { existsSync, readdirSync, rmSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import pc from 'picocolors';
5
+ import { configExists, readConfig } from '../config.js';
6
+ import { getEntry, getComponentNames, registry } from '../registry.js';
7
+ import { getOrCreateLockfile, writeLockfile } from '../lockfile.js';
8
+ /**
9
+ * Removes one installed UI component from the user's project, and offers to
10
+ * also remove any dependencies that would become orphaned (installed but no
11
+ * longer referenced by any remaining installed component).
12
+ *
13
+ * Two safety nets:
14
+ * - **Dependents check** — if other installed components still depend on
15
+ * this one, warn before removal because removing it would break them.
16
+ * - **Orphan detection** — `findOrphans` walks the registry to find
17
+ * dependencies that became "dead weight" after this removal. The user
18
+ * opts in via prompt (default yes — cleanup is usually what they want).
19
+ *
20
+ * `--force` skips both prompts: dependents are removed anyway, and orphans
21
+ * are auto-removed without asking.
22
+ */
23
+ export const removeCommand = async (component, options) => {
24
+ const cwd = process.cwd();
25
+ p.intro(pc.bold('dolan remove'));
26
+ if (!configExists(cwd)) {
27
+ p.log.error(`No ${pc.cyan('dolan.config.json')} found. Run ${pc.bold('dolan init')} first.`);
28
+ process.exit(1);
29
+ }
30
+ const entry = getEntry(component);
31
+ if (!entry) {
32
+ p.log.error(`Unknown component ${pc.bold(component)}. Available: ${getComponentNames().join(', ')}`);
33
+ process.exit(1);
34
+ }
35
+ const config = readConfig(cwd);
36
+ const componentsDir = resolve(cwd, config.aliases.components);
37
+ const componentDir = resolve(componentsDir, component);
38
+ if (!existsSync(componentDir)) {
39
+ p.log.error(`${pc.bold(component)} is not installed.`);
40
+ process.exit(1);
41
+ }
42
+ // Determine what's currently installed by intersecting the components dir
43
+ // with the registry — directories we don't recognize from the registry are
44
+ // assumed to be user-owned and ignored. The Set lookup is required for the
45
+ // O(1) `installed.has()` checks inside the dependents filter below.
46
+ const allKnown = new Set(getComponentNames());
47
+ const installed = new Set(
48
+ // The `: []` fallback is unreachable in practice: we already confirmed
49
+ // `componentDir` (a child of `componentsDir`) exists above, which implies
50
+ // `componentsDir` itself exists. Kept as a defensive guard rather than a
51
+ // non-null assertion, in case this function is ever called from a path
52
+ // that skips that earlier check.
53
+ /* v8 ignore next 5 */
54
+ existsSync(componentsDir)
55
+ ? readdirSync(componentsDir, { withFileTypes: true })
56
+ .filter((e) => e.isDirectory() && allKnown.has(e.name))
57
+ .map((e) => e.name)
58
+ : []);
59
+ // A component is a "dependent" if (a) the registry lists `component` in its
60
+ // dependencies array AND (b) it's currently installed. The self-exclusion
61
+ // guard (`r.name !== component`) handles the degenerate case of a component
62
+ // appearing in its own dependency list — shouldn't happen, but it would
63
+ // produce a misleading warning if it did.
64
+ const dependents = registry.filter((r) => r.dependencies.includes(component) &&
65
+ installed.has(r.name) &&
66
+ r.name !== component);
67
+ if (dependents.length > 0 && !options.force) {
68
+ p.log.warn(`The following installed components depend on ${pc.bold(component)}: ${dependents.map((d) => pc.bold(d.name)).join(', ')}`);
69
+ const proceed = await p.confirm({
70
+ message: 'Remove anyway? This may break those components.',
71
+ initialValue: false,
72
+ });
73
+ if (p.isCancel(proceed) || !proceed) {
74
+ p.cancel('Removal canceled.');
75
+ process.exit(0);
76
+ }
77
+ }
78
+ // Identify orphaned dependencies
79
+ const removalSet = new Set([component]);
80
+ if (entry.dependencies.length > 0) {
81
+ const orphans = findOrphans(component, installed, removalSet);
82
+ if (orphans.length > 0 && !options.force) {
83
+ const removeOrphans = await p.confirm({
84
+ message: `Also remove orphaned dependencies? (${orphans.map((o) => pc.bold(o)).join(', ')})`,
85
+ initialValue: true,
86
+ });
87
+ if (!p.isCancel(removeOrphans) && removeOrphans) {
88
+ for (const orphan of orphans) {
89
+ removalSet.add(orphan);
90
+ }
91
+ }
92
+ }
93
+ else if (options.force) {
94
+ for (const orphan of findOrphans(component, installed, removalSet)) {
95
+ removalSet.add(orphan);
96
+ }
97
+ }
98
+ }
99
+ // Perform removal
100
+ const lockfile = getOrCreateLockfile(cwd);
101
+ for (const name of removalSet) {
102
+ const dir = resolve(componentsDir, name);
103
+ if (existsSync(dir)) {
104
+ rmSync(dir, { recursive: true });
105
+ }
106
+ delete lockfile.components[name];
107
+ }
108
+ writeLockfile(cwd, lockfile);
109
+ const removed = [...removalSet].sort();
110
+ p.log.success(`Removed: ${removed.map((n) => pc.bold(n)).join(', ')}`);
111
+ p.outro('Done.');
112
+ };
113
+ /**
114
+ * Find dependencies of `target` that are installed but no longer needed by
115
+ * any other installed component (excluding those already in the removal set).
116
+ *
117
+ * Algorithm: for each direct dependency of the target, ask "is any OTHER
118
+ * installed component (that isn't itself being removed) still referencing
119
+ * this dependency?" — if no, it's orphaned.
120
+ *
121
+ * Note: this is intentionally single-level, not transitive. If A depends on B
122
+ * which depends on C, and we remove A, we'll detect B as orphaned but won't
123
+ * automatically detect C — the user would need to re-run remove on B (or run
124
+ * `dolan doctor` which scans for all orphans). Transitive orphan detection
125
+ * here would require a fixed-point iteration and is overkill given how short
126
+ * component dependency chains typically are (1-2 levels deep).
127
+ */
128
+ const findOrphans = (target, installed, removalSet) => {
129
+ const targetEntry = getEntry(target);
130
+ // Unreachable in practice: every call site passes a `target` that
131
+ // `removeCommand` already resolved via the same `getEntry` lookup (and
132
+ // exited earlier if it were unknown), so this can't be null here.
133
+ /* v8 ignore next */
134
+ if (!targetEntry)
135
+ return [];
136
+ const orphans = [];
137
+ for (const dep of targetEntry.dependencies) {
138
+ // Skip deps that aren't actually installed (e.g. the user removed them
139
+ // manually) — there's nothing to orphan.
140
+ if (!installed.has(dep))
141
+ continue;
142
+ // Skip deps already queued for removal — avoid double-reporting. Only
143
+ // reachable if a component depended on itself (a registry data bug);
144
+ // `removalSet` holds just `target` for the single findOrphans() call
145
+ // each removal makes, so this guards against corrupt registry data
146
+ // rather than anything the current call sites can produce.
147
+ /* v8 ignore next */
148
+ if (removalSet.has(dep))
149
+ continue;
150
+ // Check if any other installed component (not being removed) depends on this
151
+ const stillNeeded = registry.some((r) => r.name !== target &&
152
+ !removalSet.has(r.name) &&
153
+ installed.has(r.name) &&
154
+ r.dependencies.includes(dep));
155
+ if (!stillNeeded) {
156
+ orphans.push(dep);
157
+ }
158
+ }
159
+ return orphans;
160
+ };
161
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};