@blotch/dolan 22.2.1 → 22.2.3
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/dist/commands/add.d.ts +6 -2
- package/dist/commands/add.js +32 -10
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.test.js +129 -9
- package/dist/commands/add.test.js.map +1 -1
- package/dist/commands/diff.d.ts +2 -1
- package/dist/commands/diff.js +38 -25
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/diff.test.js +72 -11
- package/dist/commands/diff.test.js.map +1 -1
- package/dist/commands/doctor.js +41 -27
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +93 -9
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/eject.js +7 -0
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/eject.test.js +39 -0
- package/dist/commands/eject.test.js.map +1 -1
- package/dist/commands/info.js +3 -2
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.d.ts +37 -1
- package/dist/commands/init.js +149 -40
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/init.test.js +285 -26
- package/dist/commands/init.test.js.map +1 -1
- package/dist/commands/install-packages.d.ts +6 -0
- package/dist/commands/install-packages.js +20 -0
- package/dist/commands/install-packages.js.map +1 -0
- package/dist/commands/install-packages.test.d.ts +1 -0
- package/dist/commands/install-packages.test.js +55 -0
- package/dist/commands/install-packages.test.js.map +1 -0
- package/dist/commands/list.js +21 -14
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/list.test.js +62 -5
- package/dist/commands/list.test.js.map +1 -1
- package/dist/commands/outdated.js +11 -10
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/outdated.test.js +20 -5
- package/dist/commands/outdated.test.js.map +1 -1
- package/dist/commands/remove.d.ts +4 -0
- package/dist/commands/remove.js +17 -4
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/remove.test.js +53 -2
- package/dist/commands/remove.test.js.map +1 -1
- package/dist/commands/update.d.ts +6 -0
- package/dist/commands/update.js +59 -24
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/update.test.js +273 -31
- package/dist/commands/update.test.js.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts +8 -0
- package/dist/registry.js +32 -24
- package/dist/registry.js.map +1 -1
- package/dist/registry.test.js +76 -37
- package/dist/registry.test.js.map +1 -1
- package/dist/testing/set-input-signal.d.ts +13 -0
- package/dist/testing/set-input-signal.js +20 -0
- package/dist/testing/set-input-signal.js.map +1 -0
- package/dist/testing/set-input-signal.test.d.ts +1 -0
- package/dist/testing/set-input-signal.test.js +20 -0
- package/dist/testing/set-input-signal.test.js.map +1 -0
- package/dist/ui/components/action-sheet/action-sheet.test.ts +48 -1
- package/dist/ui/components/action-sheet/action-sheet.ts +37 -9
- package/dist/ui/components/alert-dialog/alert-dialog.test.ts +49 -2
- package/dist/ui/components/alert-dialog/alert-dialog.ts +43 -12
- package/dist/ui/components/area-chart/area-chart-render.test.ts +52 -110
- package/dist/ui/components/area-chart/area-chart.test.ts +59 -146
- package/dist/ui/components/area-chart/area-chart.ts +100 -315
- package/dist/ui/components/area-chart/index.ts +2 -3
- package/dist/ui/components/bar-chart/bar-chart-render.test.ts +47 -163
- package/dist/ui/components/bar-chart/bar-chart.test.ts +82 -58
- package/dist/ui/components/bar-chart/bar-chart.ts +140 -294
- package/dist/ui/components/bar-chart/index.ts +3 -3
- package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +191 -9
- package/dist/ui/components/bottom-sheet/bottom-sheet.ts +136 -20
- package/dist/ui/components/button/button-render.test.ts +19 -0
- package/dist/ui/components/button/button.test.ts +2 -15
- package/dist/ui/components/button/button.ts +18 -2
- package/dist/ui/components/button-group/button-group.test.ts +2 -21
- package/dist/ui/components/candlestick-chart/candlestick-chart-render.test.ts +48 -163
- package/dist/ui/components/candlestick-chart/candlestick-chart.test.ts +107 -85
- package/dist/ui/components/candlestick-chart/candlestick-chart.ts +150 -323
- package/dist/ui/components/candlestick-chart/index.ts +3 -4
- package/dist/ui/components/chart/chart-focus.test.ts +132 -0
- package/dist/ui/components/chart/chart-focus.ts +115 -0
- package/dist/ui/components/chart/chart-presets.test.ts +139 -0
- package/dist/ui/components/chart/chart-presets.ts +271 -0
- package/dist/ui/components/chart/chart-render.test.ts +730 -0
- package/dist/ui/components/chart/chart-scene.test.ts +589 -0
- package/dist/ui/components/chart/chart-scene.ts +483 -0
- package/dist/ui/components/chart/chart-theme.test.ts +85 -0
- package/dist/ui/components/chart/chart-theme.ts +198 -0
- package/dist/ui/components/chart/chart-zoom.test.ts +159 -0
- package/dist/ui/components/chart/chart-zoom.ts +162 -0
- package/dist/ui/components/chart/chart.ts +921 -0
- package/dist/ui/components/chart/index.ts +24 -0
- package/dist/ui/components/dialog/dialog.test.ts +49 -2
- package/dist/ui/components/dialog/dialog.ts +43 -12
- package/dist/ui/components/icon/icon-theme.test.ts +133 -0
- package/dist/ui/components/icon/icon-theme.ts +204 -0
- package/dist/ui/components/icon/icon.test.ts +51 -2
- package/dist/ui/components/icon/icon.ts +38 -21
- package/dist/ui/components/line-chart/index.ts +2 -3
- package/dist/ui/components/line-chart/line-chart-render.test.ts +69 -107
- package/dist/ui/components/line-chart/line-chart.test.ts +63 -67
- package/dist/ui/components/line-chart/line-chart.ts +83 -241
- package/dist/ui/components/list/list.test.ts +69 -2
- package/dist/ui/components/list/list.ts +21 -15
- package/dist/ui/components/nav-drawer/nav-drawer.test.ts +80 -1
- package/dist/ui/components/nav-drawer/nav-drawer.ts +66 -11
- package/dist/ui/components/pagination/pagination.test.ts +62 -0
- package/dist/ui/components/pagination/pagination.ts +55 -8
- package/dist/ui/components/scatter-chart/index.ts +2 -3
- package/dist/ui/components/scatter-chart/scatter-chart-render.test.ts +51 -144
- package/dist/ui/components/scatter-chart/scatter-chart.test.ts +57 -47
- package/dist/ui/components/scatter-chart/scatter-chart.ts +104 -250
- package/dist/ui/components/scroll-area/scroll-area.test.ts +37 -2
- package/dist/ui/components/scroll-area/scroll-area.ts +8 -8
- package/dist/ui/components/spinner/spinner.test.ts +27 -0
- package/dist/ui/components/spinner/spinner.ts +33 -23
- package/dist/ui/components/toast/toast.test.ts +37 -0
- package/dist/ui/components/toast/toast.ts +20 -4
- package/dist/ui/theme/chart-colors.test.ts +30 -0
- package/dist/ui/theme/dark.css +8 -0
- package/dist/ui/theme/default.css +8 -0
- package/dist/ui/theme/icon-colors.test.ts +30 -0
- package/dist/ui/theme/tailwind-plugin.ts +10 -1
- package/dist/utils/installed.d.ts +17 -0
- package/dist/utils/installed.js +27 -0
- package/dist/utils/installed.js.map +1 -0
- package/dist/utils/installed.test.d.ts +1 -0
- package/dist/utils/installed.test.js +41 -0
- package/dist/utils/installed.test.js.map +1 -0
- package/dist/utils/interactive.d.ts +9 -0
- package/dist/utils/interactive.js +10 -0
- package/dist/utils/interactive.js.map +1 -0
- package/dist/utils/interactive.test.d.ts +1 -0
- package/dist/utils/interactive.test.js +24 -0
- package/dist/utils/interactive.test.js.map +1 -0
- package/dist/utils/packages.d.ts +36 -0
- package/dist/utils/packages.js +70 -0
- package/dist/utils/packages.js.map +1 -0
- package/dist/utils/packages.test.d.ts +1 -0
- package/dist/utils/packages.test.js +89 -0
- package/dist/utils/packages.test.js.map +1 -0
- package/dist/utils/resolve-paths.d.ts +17 -1
- package/dist/utils/resolve-paths.js +23 -3
- package/dist/utils/resolve-paths.js.map +1 -1
- package/dist/utils/resolve-paths.test.js +34 -2
- package/dist/utils/resolve-paths.test.js.map +1 -1
- package/package.json +5 -1
- package/dist/ui/components/cartesian-chart/cartesian-chart-render.test.ts +0 -188
- package/dist/ui/components/cartesian-chart/cartesian-chart.test.ts +0 -549
- package/dist/ui/components/cartesian-chart/cartesian-chart.ts +0 -1140
- package/dist/ui/components/cartesian-chart/index.ts +0 -18
|
@@ -20,6 +20,12 @@ vi.mock('@clack/prompts', () => ({
|
|
|
20
20
|
cancel: vi.fn(),
|
|
21
21
|
isCancel: vi.fn().mockReturnValue(false),
|
|
22
22
|
}));
|
|
23
|
+
// Vitest's stdin isn't a terminal, which reads as "nobody can answer". Most
|
|
24
|
+
// tests are about the questions, so they run as if in one.
|
|
25
|
+
let interactive = true;
|
|
26
|
+
vi.mock('../utils/interactive.js', () => ({
|
|
27
|
+
isInteractive: () => interactive,
|
|
28
|
+
}));
|
|
23
29
|
let fixture;
|
|
24
30
|
vi.mock('../utils/resolve-paths.js', () => ({
|
|
25
31
|
getUiSourceDir: () => fixture.uiDir,
|
|
@@ -27,7 +33,16 @@ vi.mock('../utils/resolve-paths.js', () => ({
|
|
|
27
33
|
getComponentFiles: (name) => readdirSync(join(fixture.uiDir, 'components', name)).filter((f) => f.endsWith('.ts')),
|
|
28
34
|
rewriteImports: (content) => content,
|
|
29
35
|
}));
|
|
36
|
+
// The install step runs the project's package manager; record calls instead.
|
|
37
|
+
const installComponentPackages = vi.fn();
|
|
38
|
+
vi.mock('./install-packages.js', () => ({
|
|
39
|
+
installComponentPackages: (...args) => installComponentPackages(...args),
|
|
40
|
+
}));
|
|
30
41
|
beforeEach(() => {
|
|
42
|
+
interactive = true;
|
|
43
|
+
// Each test sees only its own calls. Without this, an assertion could pass
|
|
44
|
+
// on a message an earlier test logged.
|
|
45
|
+
vi.clearAllMocks();
|
|
31
46
|
vi.spyOn(process, 'exit').mockImplementation((code) => {
|
|
32
47
|
throw new Error(`process.exit(${code})`);
|
|
33
48
|
});
|
|
@@ -91,28 +106,28 @@ describe('updateCommand --selective', () => {
|
|
|
91
106
|
it('handles mixed decisions across multiple files', async () => {
|
|
92
107
|
const cardOriginal = 'export const Card = { v: 1 };';
|
|
93
108
|
const cardUpstream = 'export const Card = { v: 2 };';
|
|
94
|
-
const
|
|
95
|
-
const
|
|
109
|
+
const skeletonOriginal = 'export const Skeleton = { v: 1 };';
|
|
110
|
+
const skeletonUpstream = 'export const Skeleton = { v: 2 };';
|
|
96
111
|
const cardHash = hashContent(cardOriginal);
|
|
97
|
-
const
|
|
112
|
+
const skeletonHash = hashContent(skeletonOriginal);
|
|
98
113
|
fixture = createFixture({
|
|
99
114
|
config: DEFAULT_CONFIG,
|
|
100
115
|
lockfile: {
|
|
101
116
|
version: 1,
|
|
102
117
|
components: {
|
|
103
118
|
card: { 'card.ts': { hash: cardHash } },
|
|
104
|
-
|
|
119
|
+
skeleton: { 'skeleton.ts': { hash: skeletonHash } },
|
|
105
120
|
},
|
|
106
121
|
utils: {},
|
|
107
122
|
theme: {},
|
|
108
123
|
},
|
|
109
124
|
components: {
|
|
110
125
|
card: { 'card.ts': cardOriginal },
|
|
111
|
-
|
|
126
|
+
skeleton: { 'skeleton.ts': skeletonOriginal },
|
|
112
127
|
},
|
|
113
128
|
uiSource: {
|
|
114
129
|
card: { 'card.ts': cardUpstream },
|
|
115
|
-
|
|
130
|
+
skeleton: { 'skeleton.ts': skeletonUpstream },
|
|
116
131
|
},
|
|
117
132
|
});
|
|
118
133
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
@@ -124,11 +139,11 @@ describe('updateCommand --selective', () => {
|
|
|
124
139
|
await updateCommand({ selective: true });
|
|
125
140
|
// Card should be updated (first select → upstream)
|
|
126
141
|
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(cardUpstream);
|
|
127
|
-
//
|
|
128
|
-
expect(readInstalledFile(fixture.dir, '
|
|
142
|
+
// Skeleton should be skipped (second select → keep)
|
|
143
|
+
expect(readInstalledFile(fixture.dir, 'skeleton', 'skeleton.ts')).toBe(skeletonOriginal);
|
|
129
144
|
const lockfile = readLockfile(fixture.dir);
|
|
130
145
|
expect(lockfile.components.card['card.ts'].hash).toBe(hashContent(cardUpstream));
|
|
131
|
-
expect(lockfile.components.
|
|
146
|
+
expect(lockfile.components.skeleton['skeleton.ts'].hash).toBe(skeletonHash);
|
|
132
147
|
});
|
|
133
148
|
it('does not create new-upstream file when user chooses skip', async () => {
|
|
134
149
|
const upstream = 'export const Card = {};';
|
|
@@ -136,7 +151,7 @@ describe('updateCommand --selective', () => {
|
|
|
136
151
|
config: DEFAULT_CONFIG,
|
|
137
152
|
lockfile: {
|
|
138
153
|
version: 1,
|
|
139
|
-
components: {},
|
|
154
|
+
components: { card: {} },
|
|
140
155
|
utils: {},
|
|
141
156
|
theme: {},
|
|
142
157
|
},
|
|
@@ -169,7 +184,6 @@ describe('updateCommand --selective', () => {
|
|
|
169
184
|
});
|
|
170
185
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
171
186
|
const p = await import('@clack/prompts');
|
|
172
|
-
p.select.mockClear();
|
|
173
187
|
const { updateCommand } = await import('./update');
|
|
174
188
|
await updateCommand({ force: true, selective: true });
|
|
175
189
|
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(upstream);
|
|
@@ -219,7 +233,6 @@ describe('updateCommand --selective', () => {
|
|
|
219
233
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
220
234
|
const p = await import('@clack/prompts');
|
|
221
235
|
p.confirm.mockResolvedValue(true);
|
|
222
|
-
p.select.mockClear();
|
|
223
236
|
const { updateCommand } = await import('./update');
|
|
224
237
|
await updateCommand({});
|
|
225
238
|
expect(p.confirm).toHaveBeenCalled();
|
|
@@ -306,8 +319,6 @@ describe('updateCommand --force', () => {
|
|
|
306
319
|
});
|
|
307
320
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
308
321
|
const p = await import('@clack/prompts');
|
|
309
|
-
p.select.mockClear();
|
|
310
|
-
p.confirm.mockClear();
|
|
311
322
|
const { updateCommand } = await import('./update');
|
|
312
323
|
await updateCommand({ force: true });
|
|
313
324
|
// Local edit discarded, file reset to upstream.
|
|
@@ -337,7 +348,6 @@ describe('updateCommand --force', () => {
|
|
|
337
348
|
});
|
|
338
349
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
339
350
|
const p = await import('@clack/prompts');
|
|
340
|
-
p.select.mockClear();
|
|
341
351
|
const { updateCommand } = await import('./update');
|
|
342
352
|
await updateCommand({ force: true });
|
|
343
353
|
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(upstream);
|
|
@@ -345,14 +355,14 @@ describe('updateCommand --force', () => {
|
|
|
345
355
|
const lockfile = readLockfile(fixture.dir);
|
|
346
356
|
expect(lockfile.components.card['card.ts'].hash).toBe(hashContent(upstream));
|
|
347
357
|
});
|
|
348
|
-
it('overwrites a drifted file with no lockfile
|
|
358
|
+
it('overwrites a drifted file with no lockfile hash (unknown base → conflict)', async () => {
|
|
349
359
|
// With no stored hash the base is unknown, so any local difference is
|
|
350
360
|
// treated as a conflict. --force must still overwrite it.
|
|
351
361
|
const userVersion = 'export const Card = { v: 1, local: true };';
|
|
352
362
|
const upstream = 'export const Card = { v: 2 };';
|
|
353
363
|
fixture = createFixture({
|
|
354
364
|
config: DEFAULT_CONFIG,
|
|
355
|
-
lockfile: { version: 1, components: {}, utils: {}, theme: {} },
|
|
365
|
+
lockfile: { version: 1, components: { card: {} }, utils: {}, theme: {} },
|
|
356
366
|
components: { card: { 'card.ts': userVersion } },
|
|
357
367
|
uiSource: { card: { 'card.ts': upstream } },
|
|
358
368
|
});
|
|
@@ -477,25 +487,25 @@ describe('updateCommand --force', () => {
|
|
|
477
487
|
version: 1,
|
|
478
488
|
components: {
|
|
479
489
|
card: { 'card.ts': { hash: hashContent('card-base') } },
|
|
480
|
-
|
|
490
|
+
skeleton: { 'skeleton.ts': { hash: hashContent('skeleton-base') } },
|
|
481
491
|
},
|
|
482
492
|
utils: {},
|
|
483
493
|
theme: {},
|
|
484
494
|
},
|
|
485
495
|
components: {
|
|
486
496
|
card: { 'card.ts': 'card-local' },
|
|
487
|
-
|
|
497
|
+
skeleton: { 'skeleton.ts': 'skeleton-local' },
|
|
488
498
|
},
|
|
489
499
|
uiSource: {
|
|
490
500
|
card: { 'card.ts': 'card-upstream' },
|
|
491
|
-
|
|
501
|
+
skeleton: { 'skeleton.ts': 'skeleton-upstream' },
|
|
492
502
|
},
|
|
493
503
|
});
|
|
494
504
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
495
505
|
const { updateCommand } = await import('./update');
|
|
496
506
|
await updateCommand({ force: true });
|
|
497
507
|
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe('card-upstream');
|
|
498
|
-
expect(readInstalledFile(fixture.dir, '
|
|
508
|
+
expect(readInstalledFile(fixture.dir, 'skeleton', 'skeleton.ts')).toBe('skeleton-upstream');
|
|
499
509
|
});
|
|
500
510
|
it('does not delete untracked local files sitting alongside components', async () => {
|
|
501
511
|
// Force overwrites tracked files but must not touch files the registry
|
|
@@ -635,8 +645,6 @@ describe('updateCommand --force', () => {
|
|
|
635
645
|
seedTheme(fixture, 'default.css', 'theme-local'); // theme conflict
|
|
636
646
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
637
647
|
const p = await import('@clack/prompts');
|
|
638
|
-
p.select.mockClear();
|
|
639
|
-
p.confirm.mockClear();
|
|
640
648
|
const { updateCommand } = await import('./update');
|
|
641
649
|
await updateCommand({ force: true });
|
|
642
650
|
expect(p.select).not.toHaveBeenCalled();
|
|
@@ -781,8 +789,6 @@ describe('updateCommand — config / no-op paths', () => {
|
|
|
781
789
|
});
|
|
782
790
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
783
791
|
const p = await import('@clack/prompts');
|
|
784
|
-
p.confirm.mockClear();
|
|
785
|
-
p.select.mockClear();
|
|
786
792
|
const { updateCommand } = await import('./update');
|
|
787
793
|
await updateCommand({});
|
|
788
794
|
// Nothing prompts — a lone user-modified file with no force/selective is
|
|
@@ -874,7 +880,6 @@ describe('updateCommand — config / no-op paths', () => {
|
|
|
874
880
|
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
875
881
|
const p = await import('@clack/prompts');
|
|
876
882
|
p.confirm.mockResolvedValueOnce(true);
|
|
877
|
-
p.select.mockClear();
|
|
878
883
|
const { updateCommand } = await import('./update');
|
|
879
884
|
await updateCommand({});
|
|
880
885
|
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(cardUpstream);
|
|
@@ -888,15 +893,15 @@ describe('updateCommand — config / no-op paths', () => {
|
|
|
888
893
|
// The already up-to-date theme file's hash is still recorded.
|
|
889
894
|
expect(lockfile.theme['default.css'].hash).toBe(hashContent(themeContent));
|
|
890
895
|
});
|
|
891
|
-
it('advances the lockfile for an up-to-date component and theme file with no
|
|
892
|
-
//
|
|
893
|
-
//
|
|
894
|
-
//
|
|
896
|
+
it('advances the lockfile for an up-to-date component with no file hashes and a theme file with no entry', async () => {
|
|
897
|
+
// The component is tracked without file hashes, and the theme file has
|
|
898
|
+
// no lockfile record at all — buildLockfile() must create fresh entries
|
|
899
|
+
// for both on the "nothing to do" fast path.
|
|
895
900
|
const cardContent = 'export const Card = {};';
|
|
896
901
|
const themeContent = ':root { --primary: rgba(1, 1, 1, 1); }';
|
|
897
902
|
fixture = createFixture({
|
|
898
903
|
config: DEFAULT_CONFIG,
|
|
899
|
-
lockfile: { version: 1, components: {}, utils: {}, theme: {} },
|
|
904
|
+
lockfile: { version: 1, components: { card: {} }, utils: {}, theme: {} },
|
|
900
905
|
components: { card: { 'card.ts': cardContent } },
|
|
901
906
|
uiSource: { card: { 'card.ts': cardContent } },
|
|
902
907
|
themeFiles: { 'default.css': themeContent },
|
|
@@ -1230,4 +1235,241 @@ describe('updateCommand — selective review of shared theme files', () => {
|
|
|
1230
1235
|
expect(lockfile.theme['default.css'].hash).toBe(hashContent(upstream));
|
|
1231
1236
|
});
|
|
1232
1237
|
});
|
|
1238
|
+
describe('updateCommand dependencies', () => {
|
|
1239
|
+
it("adds a dependency a component's new version needs, and its packages", async () => {
|
|
1240
|
+
// line-chart used to stand alone; upstream it now builds on chart, which
|
|
1241
|
+
// the project doesn't have yet.
|
|
1242
|
+
const lineChart = "import { UiChart } from '../chart/chart';";
|
|
1243
|
+
fixture = createFixture({
|
|
1244
|
+
config: DEFAULT_CONFIG,
|
|
1245
|
+
lockfile: {
|
|
1246
|
+
version: 1,
|
|
1247
|
+
components: {
|
|
1248
|
+
'line-chart': { 'line-chart.ts': { hash: hashContent('old') } },
|
|
1249
|
+
},
|
|
1250
|
+
utils: {},
|
|
1251
|
+
theme: {},
|
|
1252
|
+
},
|
|
1253
|
+
components: { 'line-chart': { 'line-chart.ts': 'old' } },
|
|
1254
|
+
uiSource: {
|
|
1255
|
+
'line-chart': { 'line-chart.ts': lineChart },
|
|
1256
|
+
chart: { 'chart.ts': 'export const UiChart = {};' },
|
|
1257
|
+
},
|
|
1258
|
+
});
|
|
1259
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1260
|
+
const { updateCommand } = await import('./update');
|
|
1261
|
+
await updateCommand({ force: true });
|
|
1262
|
+
expect(readInstalledFile(fixture.dir, 'chart', 'chart.ts')).toBe('export const UiChart = {};');
|
|
1263
|
+
expect(readInstalledFile(fixture.dir, 'line-chart', 'line-chart.ts')).toBe(lineChart);
|
|
1264
|
+
expect(installComponentPackages).toHaveBeenCalledWith(fixture.dir, [
|
|
1265
|
+
'chart',
|
|
1266
|
+
'line-chart',
|
|
1267
|
+
]);
|
|
1268
|
+
});
|
|
1269
|
+
it('leaves out a new dependency the user skips in selective mode', async () => {
|
|
1270
|
+
const lineChart = "import { UiChart } from '../chart/chart';";
|
|
1271
|
+
fixture = createFixture({
|
|
1272
|
+
config: DEFAULT_CONFIG,
|
|
1273
|
+
lockfile: {
|
|
1274
|
+
version: 1,
|
|
1275
|
+
components: {
|
|
1276
|
+
'line-chart': { 'line-chart.ts': { hash: hashContent(lineChart) } },
|
|
1277
|
+
},
|
|
1278
|
+
utils: {},
|
|
1279
|
+
theme: {},
|
|
1280
|
+
},
|
|
1281
|
+
components: { 'line-chart': { 'line-chart.ts': lineChart } },
|
|
1282
|
+
uiSource: {
|
|
1283
|
+
'line-chart': { 'line-chart.ts': lineChart },
|
|
1284
|
+
chart: { 'chart.ts': 'export const UiChart = {};' },
|
|
1285
|
+
},
|
|
1286
|
+
});
|
|
1287
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1288
|
+
const p = await import('@clack/prompts');
|
|
1289
|
+
p.select.mockResolvedValueOnce('keep');
|
|
1290
|
+
const { updateCommand } = await import('./update');
|
|
1291
|
+
await updateCommand({ selective: true });
|
|
1292
|
+
expect(existsSync(join(fixture.dir, DEFAULT_CONFIG.aliases.components, 'chart/chart.ts'))).toBe(false);
|
|
1293
|
+
expect(readLockfile(fixture.dir).components['chart']).toEqual({});
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
describe('updateCommand — ejected components', () => {
|
|
1297
|
+
/**
|
|
1298
|
+
* `dolan eject card` deleted card's lockfile entry and kept its files,
|
|
1299
|
+
* which the app has since changed.
|
|
1300
|
+
*/
|
|
1301
|
+
const ejectedCard = (lockfileComponents = {}) => createFixture({
|
|
1302
|
+
config: DEFAULT_CONFIG,
|
|
1303
|
+
lockfile: {
|
|
1304
|
+
version: 1,
|
|
1305
|
+
components: lockfileComponents,
|
|
1306
|
+
utils: {},
|
|
1307
|
+
theme: {},
|
|
1308
|
+
},
|
|
1309
|
+
components: {
|
|
1310
|
+
card: { 'card.ts': 'export const Card = { mine: true };' },
|
|
1311
|
+
},
|
|
1312
|
+
uiSource: { card: { 'card.ts': 'export const Card = { v: 2 };' } },
|
|
1313
|
+
});
|
|
1314
|
+
it("doesn't overwrite or track them again, even with --force", async () => {
|
|
1315
|
+
fixture = ejectedCard();
|
|
1316
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1317
|
+
const { updateCommand } = await import('./update');
|
|
1318
|
+
await updateCommand({ force: true });
|
|
1319
|
+
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe('export const Card = { mine: true };');
|
|
1320
|
+
expect(readLockfile(fixture.dir).components).not.toHaveProperty('card');
|
|
1321
|
+
});
|
|
1322
|
+
it("doesn't report them as a conflict", async () => {
|
|
1323
|
+
fixture = ejectedCard();
|
|
1324
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1325
|
+
const p = await import('@clack/prompts');
|
|
1326
|
+
const { updateCommand } = await import('./update');
|
|
1327
|
+
await updateCommand({});
|
|
1328
|
+
const messages = p.log.message.mock.calls
|
|
1329
|
+
.map((c) => c[0])
|
|
1330
|
+
.join('\n');
|
|
1331
|
+
expect(messages).not.toContain('card');
|
|
1332
|
+
expect(p.select).not.toHaveBeenCalled();
|
|
1333
|
+
});
|
|
1334
|
+
it('leaves an ejected dependency of a tracked component alone', async () => {
|
|
1335
|
+
// select is tracked and depends on bottom-sheet, which was ejected.
|
|
1336
|
+
const select = 'export const Select = {};';
|
|
1337
|
+
fixture = createFixture({
|
|
1338
|
+
config: DEFAULT_CONFIG,
|
|
1339
|
+
lockfile: {
|
|
1340
|
+
version: 1,
|
|
1341
|
+
components: { select: { 'select.ts': { hash: hashContent(select) } } },
|
|
1342
|
+
utils: {},
|
|
1343
|
+
theme: {},
|
|
1344
|
+
},
|
|
1345
|
+
components: {
|
|
1346
|
+
select: { 'select.ts': select },
|
|
1347
|
+
'bottom-sheet': {
|
|
1348
|
+
'bottom-sheet.ts': 'export const BottomSheet = { mine: true };',
|
|
1349
|
+
},
|
|
1350
|
+
},
|
|
1351
|
+
uiSource: {
|
|
1352
|
+
select: { 'select.ts': select },
|
|
1353
|
+
'bottom-sheet': { 'bottom-sheet.ts': 'export const BottomSheet = {};' },
|
|
1354
|
+
},
|
|
1355
|
+
});
|
|
1356
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1357
|
+
const { updateCommand } = await import('./update');
|
|
1358
|
+
await updateCommand({ force: true });
|
|
1359
|
+
expect(readInstalledFile(fixture.dir, 'bottom-sheet', 'bottom-sheet.ts')).toBe('export const BottomSheet = { mine: true };');
|
|
1360
|
+
expect(readLockfile(fixture.dir).components).not.toHaveProperty('bottom-sheet');
|
|
1361
|
+
});
|
|
1362
|
+
});
|
|
1363
|
+
// CI, agents and scripts: a question there would wait for input that never
|
|
1364
|
+
// comes.
|
|
1365
|
+
describe('updateCommand without a terminal', () => {
|
|
1366
|
+
const base = 'export const Card = { v: 1 };';
|
|
1367
|
+
const userVersion = 'export const Card = { v: 1, local: true };';
|
|
1368
|
+
const upstream = 'export const Card = { v: 2 };';
|
|
1369
|
+
const themeBase = ':root { --primary: rgba(1, 1, 1, 1); }';
|
|
1370
|
+
const themeMine = ':root { --primary: rgba(9, 9, 9, 1); }';
|
|
1371
|
+
const themeUpstream = ':root { --primary: rgba(2, 2, 2, 1); }';
|
|
1372
|
+
/**
|
|
1373
|
+
* `card` and `default.css` conflict (both sides changed), and `skeleton` is
|
|
1374
|
+
* a plain auto-update.
|
|
1375
|
+
*/
|
|
1376
|
+
const setup = () => {
|
|
1377
|
+
fixture = createFixture({
|
|
1378
|
+
config: DEFAULT_CONFIG,
|
|
1379
|
+
lockfile: {
|
|
1380
|
+
version: 1,
|
|
1381
|
+
components: {
|
|
1382
|
+
card: { 'card.ts': { hash: hashContent(base) } },
|
|
1383
|
+
skeleton: { 'skeleton.ts': { hash: hashContent(base) } },
|
|
1384
|
+
},
|
|
1385
|
+
utils: {},
|
|
1386
|
+
theme: { 'default.css': { hash: hashContent(themeBase) } },
|
|
1387
|
+
},
|
|
1388
|
+
components: {
|
|
1389
|
+
card: { 'card.ts': userVersion },
|
|
1390
|
+
skeleton: { 'skeleton.ts': base },
|
|
1391
|
+
},
|
|
1392
|
+
uiSource: {
|
|
1393
|
+
card: { 'card.ts': upstream },
|
|
1394
|
+
skeleton: { 'skeleton.ts': upstream },
|
|
1395
|
+
},
|
|
1396
|
+
themeFiles: { 'default.css': themeUpstream },
|
|
1397
|
+
});
|
|
1398
|
+
writeFileSync(join(fixture.dir, DEFAULT_CONFIG.aliases.theme, 'default.css'), themeMine);
|
|
1399
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1400
|
+
};
|
|
1401
|
+
const readTheme = () => readFileSync(join(fixture.dir, DEFAULT_CONFIG.aliases.theme, 'default.css'), 'utf-8');
|
|
1402
|
+
beforeEach(() => {
|
|
1403
|
+
interactive = false;
|
|
1404
|
+
});
|
|
1405
|
+
it('applies auto-updates without asking', async () => {
|
|
1406
|
+
fixture = createFixture({
|
|
1407
|
+
config: DEFAULT_CONFIG,
|
|
1408
|
+
lockfile: {
|
|
1409
|
+
version: 1,
|
|
1410
|
+
components: { card: { 'card.ts': { hash: hashContent(base) } } },
|
|
1411
|
+
utils: {},
|
|
1412
|
+
theme: {},
|
|
1413
|
+
},
|
|
1414
|
+
components: { card: { 'card.ts': base } },
|
|
1415
|
+
uiSource: { card: { 'card.ts': upstream } },
|
|
1416
|
+
});
|
|
1417
|
+
vi.spyOn(process, 'cwd').mockReturnValue(fixture.dir);
|
|
1418
|
+
const p = await import('@clack/prompts');
|
|
1419
|
+
const { updateCommand } = await import('./update');
|
|
1420
|
+
await updateCommand({});
|
|
1421
|
+
expect(p.confirm).not.toHaveBeenCalled();
|
|
1422
|
+
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(upstream);
|
|
1423
|
+
expect(p.outro).toHaveBeenCalledWith('Update complete.');
|
|
1424
|
+
});
|
|
1425
|
+
it('leaves conflicts as they are for a terminal to ask about, and exits 1', async () => {
|
|
1426
|
+
setup();
|
|
1427
|
+
const p = await import('@clack/prompts');
|
|
1428
|
+
const { updateCommand } = await import('./update');
|
|
1429
|
+
await expect(updateCommand({})).rejects.toThrow('process.exit(1)');
|
|
1430
|
+
expect(p.select).not.toHaveBeenCalled();
|
|
1431
|
+
// The count is bold, and CI turns colors on, so match the plain text.
|
|
1432
|
+
const [warning] = p.log.warn.mock.calls[0];
|
|
1433
|
+
// oxlint-disable-next-line no-control-regex -- matching ANSI color codes
|
|
1434
|
+
expect(warning.replace(/\u001b\[\d+m/g, '')).toMatch(/2 conflict\(s\) left.*dolan update --force/);
|
|
1435
|
+
// The auto-update still applies.
|
|
1436
|
+
expect(readInstalledFile(fixture.dir, 'skeleton', 'skeleton.ts')).toBe(upstream);
|
|
1437
|
+
// The conflicts keep both their files and their lockfile base. Keeping
|
|
1438
|
+
// the user's version would advance the base and lose the upstream change.
|
|
1439
|
+
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(userVersion);
|
|
1440
|
+
expect(readTheme()).toBe(themeMine);
|
|
1441
|
+
const lockfile = readLockfile(fixture.dir);
|
|
1442
|
+
expect(lockfile.components.card['card.ts'].hash).toBe(hashContent(base));
|
|
1443
|
+
expect(lockfile.theme['default.css'].hash).toBe(hashContent(themeBase));
|
|
1444
|
+
// So an update in a terminal still asks about both.
|
|
1445
|
+
interactive = true;
|
|
1446
|
+
vi.clearAllMocks();
|
|
1447
|
+
// A reset drops answers an earlier test queued and never used.
|
|
1448
|
+
p.select
|
|
1449
|
+
.mockReset()
|
|
1450
|
+
.mockResolvedValue('upstream');
|
|
1451
|
+
await updateCommand({});
|
|
1452
|
+
expect(p.select).toHaveBeenCalledTimes(2);
|
|
1453
|
+
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(upstream);
|
|
1454
|
+
expect(readTheme()).toBe(themeUpstream);
|
|
1455
|
+
});
|
|
1456
|
+
it("takes upstream's version of conflicts with --force, which wins over --selective", async () => {
|
|
1457
|
+
setup();
|
|
1458
|
+
const p = await import('@clack/prompts');
|
|
1459
|
+
const { updateCommand } = await import('./update');
|
|
1460
|
+
await updateCommand({ force: true, selective: true });
|
|
1461
|
+
expect(p.log.error).not.toHaveBeenCalled();
|
|
1462
|
+
expect(readInstalledFile(fixture.dir, 'card', 'card.ts')).toBe(upstream);
|
|
1463
|
+
expect(readTheme()).toBe(themeUpstream);
|
|
1464
|
+
expect(p.outro).toHaveBeenCalledWith('Update complete.');
|
|
1465
|
+
});
|
|
1466
|
+
it('fails with --selective, which asks about each file', async () => {
|
|
1467
|
+
setup();
|
|
1468
|
+
const p = await import('@clack/prompts');
|
|
1469
|
+
const { updateCommand } = await import('./update');
|
|
1470
|
+
await expect(updateCommand({ selective: true })).rejects.toThrow('process.exit(1)');
|
|
1471
|
+
expect(p.log.error).toHaveBeenCalledWith(expect.stringContaining('--selective'));
|
|
1472
|
+
expect(readInstalledFile(fixture.dir, 'skeleton', 'skeleton.ts')).toBe(base);
|
|
1473
|
+
});
|
|
1474
|
+
});
|
|
1233
1475
|
//# sourceMappingURL=update.test.js.map
|