@gilav21/shadcn-angular 0.0.24 → 0.0.26
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 +2 -0
- package/dist/commands/add.js +169 -114
- package/dist/commands/add.spec.js +17 -23
- package/dist/commands/diff.d.ts +8 -0
- package/dist/commands/diff.js +99 -0
- package/dist/commands/help.js +15 -6
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +171 -185
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +50 -0
- package/dist/index.js +21 -1
- package/dist/registry/index.d.ts +122 -12
- package/dist/registry/index.js +59 -158
- package/dist/utils/config.d.ts +1 -1
- package/dist/utils/config.js +22 -2
- package/dist/utils/paths.d.ts +7 -0
- package/dist/utils/paths.js +43 -0
- package/dist/utils/shortcut-registry.js +1 -13
- package/package.json +1 -1
- package/scripts/sync-registry.ts +347 -0
- package/src/commands/add.spec.ts +22 -32
- package/src/commands/add.ts +211 -137
- package/src/commands/diff.ts +133 -0
- package/src/commands/help.ts +15 -6
- package/src/commands/init.ts +329 -314
- package/src/commands/list.ts +66 -0
- package/src/index.ts +24 -1
- package/src/registry/index.ts +73 -169
- package/src/utils/config.ts +22 -3
- package/src/utils/paths.ts +52 -0
- package/src/utils/shortcut-registry.ts +1 -15
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getConfig } from '../utils/config.js';
|
|
5
|
+
import { registry, getComponentNames } from '../registry/index.js';
|
|
6
|
+
import { resolveProjectPath, aliasToProjectPath } from '../utils/paths.js';
|
|
7
|
+
|
|
8
|
+
type Status = 'installed' | 'not installed';
|
|
9
|
+
|
|
10
|
+
interface ComponentStatus {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly status: Status;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function list() {
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
|
|
18
|
+
const config = await getConfig(cwd);
|
|
19
|
+
if (!config) {
|
|
20
|
+
console.log(chalk.red('Error: components.json not found.'));
|
|
21
|
+
console.log(chalk.dim('Run `npx @gilav21/shadcn-angular init` first.'));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const uiBasePath = aliasToProjectPath(config.aliases.ui || 'src/components/ui');
|
|
26
|
+
const targetDir = resolveProjectPath(cwd, uiBasePath);
|
|
27
|
+
|
|
28
|
+
const statuses: ComponentStatus[] = [];
|
|
29
|
+
|
|
30
|
+
for (const name of getComponentNames()) {
|
|
31
|
+
const component = registry[name];
|
|
32
|
+
const allPresent = await allFilesExist(component.files, targetDir);
|
|
33
|
+
statuses.push({
|
|
34
|
+
name,
|
|
35
|
+
status: allPresent ? 'installed' : 'not installed',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const installed = statuses.filter(s => s.status === 'installed').sort((a, b) => a.name.localeCompare(b.name));
|
|
40
|
+
const notInstalled = statuses.filter(s => s.status === 'not installed').sort((a, b) => a.name.localeCompare(b.name));
|
|
41
|
+
|
|
42
|
+
console.log(chalk.bold(`\nInstalled (${installed.length}):`));
|
|
43
|
+
if (installed.length === 0) {
|
|
44
|
+
console.log(chalk.dim(' None'));
|
|
45
|
+
} else {
|
|
46
|
+
for (const s of installed) {
|
|
47
|
+
console.log(chalk.green(' ✓ ') + s.name);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(chalk.bold(`\nAvailable (${notInstalled.length}):`));
|
|
52
|
+
for (const s of notInstalled) {
|
|
53
|
+
console.log(chalk.dim(' - ') + s.name);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function allFilesExist(files: readonly string[], targetDir: string): Promise<boolean> {
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
if (!await fs.pathExists(path.join(targetDir, file))) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import { init } from './commands/init.js';
|
|
4
5
|
import { add } from './commands/add.js';
|
|
6
|
+
import { diff } from './commands/diff.js';
|
|
7
|
+
import { list } from './commands/list.js';
|
|
5
8
|
import { help } from './commands/help.js';
|
|
6
9
|
|
|
10
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8')) as { version: string };
|
|
11
|
+
|
|
7
12
|
const program = new Command();
|
|
8
13
|
|
|
9
14
|
program
|
|
10
15
|
.name('shadcn-angular')
|
|
11
16
|
.description('CLI for adding shadcn-angular components to your Angular project')
|
|
12
|
-
.version(
|
|
17
|
+
.version(pkg.version);
|
|
13
18
|
|
|
14
19
|
program
|
|
15
20
|
.command('init')
|
|
16
21
|
.description('Initialize shadcn-angular in your project')
|
|
17
22
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
18
23
|
.option('-d, --defaults', 'Use default configuration')
|
|
24
|
+
.option('--remote', 'Force remote fetch from GitHub registry')
|
|
19
25
|
.option('-b, --branch <branch>', 'GitHub branch to fetch components from', 'master')
|
|
26
|
+
.option('-r, --registry <url>', 'Custom registry base URL (e.g., https://gitlab.com/org/repo/-/raw/main/packages/components)')
|
|
20
27
|
.action(init);
|
|
21
28
|
|
|
22
29
|
program
|
|
@@ -28,9 +35,25 @@ program
|
|
|
28
35
|
.option('-a, --all', 'Add all available components')
|
|
29
36
|
.option('-p, --path <path>', 'The path to add the component to')
|
|
30
37
|
.option('--remote', 'Force remote fetch from GitHub registry')
|
|
38
|
+
.option('--dry-run', 'Show what would be installed without making changes')
|
|
31
39
|
.option('-b, --branch <branch>', 'GitHub branch to fetch components from', 'master')
|
|
40
|
+
.option('-r, --registry <url>', 'Custom registry base URL (overrides components.json)')
|
|
32
41
|
.action(add);
|
|
33
42
|
|
|
43
|
+
program
|
|
44
|
+
.command('diff')
|
|
45
|
+
.description('Show differences between local and remote component versions')
|
|
46
|
+
.argument('[components...]', 'Components to diff (all installed if omitted)')
|
|
47
|
+
.option('--remote', 'Force remote fetch from GitHub registry')
|
|
48
|
+
.option('-b, --branch <branch>', 'GitHub branch to fetch from', 'master')
|
|
49
|
+
.option('-r, --registry <url>', 'Custom registry base URL')
|
|
50
|
+
.action(diff);
|
|
51
|
+
|
|
52
|
+
program
|
|
53
|
+
.command('list')
|
|
54
|
+
.description('List all components and their install status')
|
|
55
|
+
.action(list);
|
|
56
|
+
|
|
34
57
|
program
|
|
35
58
|
.command('help')
|
|
36
59
|
.description('Show detailed usage information')
|
package/src/registry/index.ts
CHANGED
|
@@ -7,25 +7,25 @@ export interface OptionalDependency {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export interface ComponentDefinition {
|
|
10
|
-
name: string;
|
|
11
|
-
files: string[];
|
|
12
|
-
peerFiles?: string[];
|
|
13
|
-
dependencies?: string[];
|
|
14
|
-
optionalDependencies?: readonly OptionalDependency[];
|
|
15
|
-
npmDependencies?: string[];
|
|
16
|
-
libFiles?: string[];
|
|
17
|
-
shortcutDefinitions?: {
|
|
18
|
-
exportName: string;
|
|
19
|
-
componentName: string;
|
|
20
|
-
sourceFile: string;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly files: readonly string[];
|
|
12
|
+
readonly peerFiles?: readonly string[];
|
|
13
|
+
readonly dependencies?: readonly string[];
|
|
14
|
+
readonly optionalDependencies?: readonly OptionalDependency[];
|
|
15
|
+
readonly npmDependencies?: readonly string[];
|
|
16
|
+
readonly libFiles?: readonly string[];
|
|
17
|
+
readonly shortcutDefinitions?: readonly {
|
|
18
|
+
readonly exportName: string;
|
|
19
|
+
readonly componentName: string;
|
|
20
|
+
readonly sourceFile: string;
|
|
21
21
|
}[];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
function defineRegistry<T extends Record<string, ComponentDefinition>>(reg: T): { readonly [K in keyof T]: ComponentDefinition } {
|
|
25
|
+
return reg;
|
|
26
|
+
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
// Files are relative to the components/ui directory
|
|
28
|
-
export const registry: Record<string, ComponentDefinition> = {
|
|
28
|
+
export const registry = defineRegistry({
|
|
29
29
|
accordion: {
|
|
30
30
|
name: 'accordion',
|
|
31
31
|
files: ['accordion.component.ts'],
|
|
@@ -33,7 +33,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
33
33
|
autocomplete: {
|
|
34
34
|
name: 'autocomplete',
|
|
35
35
|
files: ['autocomplete.component.ts', 'highlight.pipe.ts'],
|
|
36
|
-
dependencies: ['
|
|
36
|
+
dependencies: ['badge', 'command', 'popover'],
|
|
37
37
|
},
|
|
38
38
|
alert: {
|
|
39
39
|
name: 'alert',
|
|
@@ -66,12 +66,11 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
66
66
|
},
|
|
67
67
|
'button-group': {
|
|
68
68
|
name: 'button-group',
|
|
69
|
-
files: ['button-group.component.ts']
|
|
70
|
-
dependencies: ['button']
|
|
69
|
+
files: ['button-group.component.ts']
|
|
71
70
|
},
|
|
72
71
|
calendar: {
|
|
73
72
|
name: 'calendar',
|
|
74
|
-
files: ['calendar.
|
|
73
|
+
files: ['calendar-locales.ts', 'calendar.component.ts'],
|
|
75
74
|
dependencies: ['button', 'select'],
|
|
76
75
|
},
|
|
77
76
|
card: {
|
|
@@ -93,7 +92,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
93
92
|
'color-picker': {
|
|
94
93
|
name: 'color-picker',
|
|
95
94
|
files: ['color-picker.component.ts'],
|
|
96
|
-
dependencies: ['
|
|
95
|
+
dependencies: ['input', 'popover', 'tabs'],
|
|
97
96
|
},
|
|
98
97
|
confetti: {
|
|
99
98
|
name: 'confetti',
|
|
@@ -103,6 +102,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
103
102
|
name: 'command',
|
|
104
103
|
files: ['command.component.ts'],
|
|
105
104
|
dependencies: ['dialog'],
|
|
105
|
+
libFiles: ['shortcut-binding.service.ts'],
|
|
106
106
|
shortcutDefinitions: [
|
|
107
107
|
{
|
|
108
108
|
exportName: 'COMMAND_DIALOG_SHORTCUT_DEFINITIONS',
|
|
@@ -113,7 +113,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
113
113
|
},
|
|
114
114
|
'context-menu': {
|
|
115
115
|
name: 'context-menu',
|
|
116
|
-
files: ['context-menu.component.ts'
|
|
116
|
+
files: ['context-menu.component.ts'],
|
|
117
117
|
},
|
|
118
118
|
'date-picker': {
|
|
119
119
|
name: 'date-picker',
|
|
@@ -123,7 +123,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
123
123
|
chat: {
|
|
124
124
|
name: 'chat',
|
|
125
125
|
files: ['chat.component.ts'],
|
|
126
|
-
dependencies: ['avatar', 'button', '
|
|
126
|
+
dependencies: ['avatar', 'button', 'scroll-area', 'textarea'],
|
|
127
127
|
},
|
|
128
128
|
'streaming-text': {
|
|
129
129
|
name: 'streaming-text',
|
|
@@ -137,7 +137,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
137
137
|
'code-block': {
|
|
138
138
|
name: 'code-block',
|
|
139
139
|
files: ['code-block.component.ts'],
|
|
140
|
-
dependencies: ['button'
|
|
140
|
+
dependencies: ['button'],
|
|
141
141
|
},
|
|
142
142
|
'text-reveal': {
|
|
143
143
|
name: 'text-reveal',
|
|
@@ -145,31 +145,11 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
145
145
|
},
|
|
146
146
|
'data-table': {
|
|
147
147
|
name: 'data-table',
|
|
148
|
-
files: [
|
|
149
|
-
'data-table/data-table.component.ts',
|
|
150
|
-
'data-table/data-table-column-header.component.ts',
|
|
151
|
-
'data-table/data-table-pagination.component.ts',
|
|
152
|
-
'data-table/data-table-multiselect-filter.component.ts',
|
|
153
|
-
'data-table/data-table.types.ts',
|
|
154
|
-
'data-table/data-table.utils.ts',
|
|
155
|
-
'data-table/index.ts',
|
|
156
|
-
],
|
|
148
|
+
files: ['calendar-locales.ts', 'data-table/component-pool.service.ts', 'data-table/data-table-column-header.component.ts', 'data-table/data-table-date-filter.component.ts', 'data-table/data-table-multiselect-filter.component.ts', 'data-table/data-table-pagination.component.ts', 'data-table/data-table.component.ts', 'data-table/data-table.types.ts', 'data-table/data-table.utils.ts', 'data-table/index.ts'],
|
|
157
149
|
peerFiles: [
|
|
158
150
|
'context-menu-integrations.ts',
|
|
159
151
|
],
|
|
160
|
-
dependencies: [
|
|
161
|
-
'table',
|
|
162
|
-
'input',
|
|
163
|
-
'button',
|
|
164
|
-
'checkbox',
|
|
165
|
-
'select',
|
|
166
|
-
'pagination',
|
|
167
|
-
'popover',
|
|
168
|
-
'component-outlet',
|
|
169
|
-
'icon',
|
|
170
|
-
'command',
|
|
171
|
-
'badge',
|
|
172
|
-
],
|
|
152
|
+
dependencies: ['badge', 'button', 'calendar', 'checkbox', 'command', 'component-outlet', 'context-menu', 'icon', 'input', 'pagination', 'popover', 'select', 'table'],
|
|
173
153
|
libFiles: ['xlsx.ts'],
|
|
174
154
|
optionalDependencies: [
|
|
175
155
|
{ name: 'context-menu', description: 'Enables right-click context menus on rows and headers' },
|
|
@@ -181,18 +161,12 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
181
161
|
},
|
|
182
162
|
dock: {
|
|
183
163
|
name: 'dock',
|
|
184
|
-
files: [
|
|
185
|
-
'dock.component.ts',
|
|
186
|
-
'dock-item.component.ts',
|
|
187
|
-
'dock-icon.component.ts',
|
|
188
|
-
'dock-label.component.ts',
|
|
189
|
-
],
|
|
190
|
-
dependencies: ['icon'],
|
|
164
|
+
files: ['dock-icon.component.ts', 'dock-item.component.ts', 'dock-label.component.ts', 'dock.component.ts'],
|
|
191
165
|
},
|
|
192
166
|
'tree-select': {
|
|
193
167
|
name: 'tree-select',
|
|
194
168
|
files: ['tree-select.component.ts'],
|
|
195
|
-
dependencies: ['popover', 'tree'
|
|
169
|
+
dependencies: ['popover', 'tree'],
|
|
196
170
|
},
|
|
197
171
|
'virtual-scroll': {
|
|
198
172
|
name: 'virtual-scroll',
|
|
@@ -221,7 +195,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
221
195
|
},
|
|
222
196
|
icon: {
|
|
223
197
|
name: 'icon',
|
|
224
|
-
files: ['icon.component.ts'],
|
|
198
|
+
files: ['icon.component.ts', 'icon.token.ts'],
|
|
225
199
|
},
|
|
226
200
|
|
|
227
201
|
'file-upload': {
|
|
@@ -233,17 +207,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
233
207
|
name: 'file-viewer',
|
|
234
208
|
files: ['file-viewer.component.ts'],
|
|
235
209
|
dependencies: ['spinner'],
|
|
236
|
-
libFiles: [
|
|
237
|
-
'file-type-detector.ts',
|
|
238
|
-
'inflate.ts',
|
|
239
|
-
'zip-reader.ts',
|
|
240
|
-
'pptx-parser.ts',
|
|
241
|
-
'xlsx-reader.ts',
|
|
242
|
-
'docx-parser.ts',
|
|
243
|
-
'doc-enhanced-parser.ts',
|
|
244
|
-
'ppt-parser.ts',
|
|
245
|
-
'svg-sanitizer.ts',
|
|
246
|
-
],
|
|
210
|
+
libFiles: ['doc-enhanced-parser.ts', 'docx-parser.ts', 'file-type-detector.ts', 'image-validator.ts', 'inflate.ts', 'ole2-reader.ts', 'ppt-parser.ts', 'pptx-parser.ts', 'svg-sanitizer.ts', 'xlsx-reader.ts', 'zip-reader.ts'],
|
|
247
211
|
},
|
|
248
212
|
'hover-card': {
|
|
249
213
|
name: 'hover-card',
|
|
@@ -251,12 +215,11 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
251
215
|
},
|
|
252
216
|
input: {
|
|
253
217
|
name: 'input',
|
|
254
|
-
files: ['input.
|
|
218
|
+
files: ['input-group.token.ts', 'input.component.ts'],
|
|
255
219
|
},
|
|
256
220
|
'input-group': {
|
|
257
221
|
name: 'input-group',
|
|
258
222
|
files: ['input-group.component.ts', 'input-group.token.ts'],
|
|
259
|
-
dependencies: ['input'],
|
|
260
223
|
},
|
|
261
224
|
'input-otp': {
|
|
262
225
|
name: 'input-otp',
|
|
@@ -329,7 +292,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
329
292
|
sidebar: {
|
|
330
293
|
name: 'sidebar',
|
|
331
294
|
files: ['sidebar.component.ts'],
|
|
332
|
-
dependencies: ['scroll-area', 'tooltip'
|
|
295
|
+
dependencies: ['scroll-area', 'tooltip'],
|
|
333
296
|
},
|
|
334
297
|
skeleton: {
|
|
335
298
|
name: 'skeleton',
|
|
@@ -361,7 +324,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
361
324
|
},
|
|
362
325
|
textarea: {
|
|
363
326
|
name: 'textarea',
|
|
364
|
-
files: ['
|
|
327
|
+
files: ['input-group.token.ts', 'textarea.component.ts'],
|
|
365
328
|
},
|
|
366
329
|
timeline: {
|
|
367
330
|
name: 'timeline',
|
|
@@ -386,51 +349,29 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
386
349
|
tree: {
|
|
387
350
|
name: 'tree',
|
|
388
351
|
files: ['tree.component.ts'],
|
|
389
|
-
dependencies: ['icon'],
|
|
390
352
|
optionalDependencies: [
|
|
391
353
|
{ name: 'context-menu', description: 'Enables right-click context menus on tree nodes' },
|
|
392
354
|
],
|
|
393
355
|
},
|
|
394
356
|
'speed-dial': {
|
|
395
357
|
name: 'speed-dial',
|
|
396
|
-
files: ['speed-dial.component.ts']
|
|
397
|
-
dependencies: ['button']
|
|
358
|
+
files: ['speed-dial.component.ts']
|
|
398
359
|
},
|
|
399
360
|
'chip-list': {
|
|
400
361
|
name: 'chip-list',
|
|
401
|
-
files: ['chip-list.component.ts'],
|
|
402
|
-
dependencies: ['badge', 'button', 'input'
|
|
362
|
+
files: ['chip-list.component.ts', 'input-group.token.ts'],
|
|
363
|
+
dependencies: ['badge', 'button', 'input'],
|
|
403
364
|
},
|
|
404
365
|
'emoji-picker': {
|
|
405
366
|
name: 'emoji-picker',
|
|
406
|
-
files: ['emoji-
|
|
367
|
+
files: ['emoji-data.ts', 'emoji-picker.component.ts'],
|
|
407
368
|
dependencies: ['input', 'scroll-area', 'tooltip'],
|
|
408
369
|
},
|
|
409
370
|
'rich-text-editor': {
|
|
410
371
|
name: 'rich-text-editor',
|
|
411
|
-
files: [
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
'rich-text-sanitizer.service.ts',
|
|
415
|
-
'rich-text-markdown.service.ts',
|
|
416
|
-
'rich-text-paste-normalizer.service.ts',
|
|
417
|
-
'rich-text-command-registry.service.ts',
|
|
418
|
-
'rich-text-mention.component.ts',
|
|
419
|
-
'rich-text-image-resizer.component.ts',
|
|
420
|
-
'rich-text-locales.ts',
|
|
421
|
-
],
|
|
422
|
-
dependencies: [
|
|
423
|
-
'button',
|
|
424
|
-
'separator',
|
|
425
|
-
'popover',
|
|
426
|
-
'emoji-picker',
|
|
427
|
-
'autocomplete',
|
|
428
|
-
'select',
|
|
429
|
-
'input',
|
|
430
|
-
'dialog',
|
|
431
|
-
'scroll-area',
|
|
432
|
-
],
|
|
433
|
-
libFiles: ['pdf-parser.ts', 'image-validator.ts', 'svg-sanitizer.ts'],
|
|
372
|
+
files: ['rich-text-command-registry.service.ts', 'rich-text-editor.component.ts', 'rich-text-image-resizer.component.ts', 'rich-text-locales.ts', 'rich-text-markdown.service.ts', 'rich-text-mention.component.ts', 'rich-text-paste-normalizer.service.ts', 'rich-text-sanitizer.service.ts', 'rich-text-toolbar.component.ts'],
|
|
373
|
+
dependencies: ['autocomplete', 'button', 'dialog', 'emoji-picker', 'popover', 'scroll-area', 'separator'],
|
|
374
|
+
libFiles: ['docx-parser.ts', 'docx-to-editor-html.ts', 'image-validator.ts', 'inflate.ts', 'pdf-parser.ts', 'shortcut-binding.service.ts', 'svg-sanitizer.ts', 'zip-reader.ts'],
|
|
434
375
|
shortcutDefinitions: [
|
|
435
376
|
{
|
|
436
377
|
exportName: 'RICH_TEXT_SHORTCUT_DEFINITIONS',
|
|
@@ -442,102 +383,54 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
442
383
|
// Chart Components
|
|
443
384
|
'pie-chart': {
|
|
444
385
|
name: 'pie-chart',
|
|
445
|
-
files: [
|
|
446
|
-
'charts/pie-chart.component.ts',
|
|
447
|
-
'charts/chart.types.ts',
|
|
448
|
-
'charts/chart.utils.ts',
|
|
449
|
-
],
|
|
386
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/pie-chart.component.ts'],
|
|
450
387
|
},
|
|
451
388
|
'pie-chart-drilldown': {
|
|
452
389
|
name: 'pie-chart-drilldown',
|
|
453
|
-
files: [
|
|
454
|
-
'charts/pie-chart-drilldown.component.ts',
|
|
455
|
-
'charts/chart.types.ts',
|
|
456
|
-
'charts/chart.utils.ts',
|
|
457
|
-
],
|
|
390
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/pie-chart-drilldown.component.ts'],
|
|
458
391
|
},
|
|
459
392
|
'bar-chart': {
|
|
460
393
|
name: 'bar-chart',
|
|
461
|
-
files: [
|
|
462
|
-
'charts/bar-chart.component.ts',
|
|
463
|
-
'charts/chart.types.ts',
|
|
464
|
-
'charts/chart.utils.ts',
|
|
465
|
-
],
|
|
394
|
+
files: ['charts/bar-chart.component.ts', 'charts/chart.types.ts', 'charts/chart.utils.ts'],
|
|
466
395
|
},
|
|
467
396
|
'bar-chart-drilldown': {
|
|
468
397
|
name: 'bar-chart-drilldown',
|
|
469
|
-
files: [
|
|
470
|
-
'charts/bar-chart-drilldown.component.ts',
|
|
471
|
-
'charts/chart.types.ts',
|
|
472
|
-
'charts/chart.utils.ts',
|
|
473
|
-
],
|
|
398
|
+
files: ['charts/bar-chart-drilldown.component.ts', 'charts/chart.types.ts', 'charts/chart.utils.ts'],
|
|
474
399
|
},
|
|
475
400
|
'stacked-bar-chart': {
|
|
476
401
|
name: 'stacked-bar-chart',
|
|
477
|
-
files: [
|
|
478
|
-
'charts/stacked-bar-chart.component.ts',
|
|
479
|
-
'charts/chart.types.ts',
|
|
480
|
-
'charts/chart.utils.ts',
|
|
481
|
-
],
|
|
402
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/stacked-bar-chart.component.ts'],
|
|
482
403
|
},
|
|
483
404
|
'column-range-chart': {
|
|
484
405
|
name: 'column-range-chart',
|
|
485
|
-
files: [
|
|
486
|
-
'charts/column-range-chart.component.ts',
|
|
487
|
-
'charts/chart.types.ts',
|
|
488
|
-
'charts/chart.utils.ts',
|
|
489
|
-
],
|
|
406
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/column-range-chart.component.ts'],
|
|
490
407
|
},
|
|
491
408
|
'bar-race-chart': {
|
|
492
409
|
name: 'bar-race-chart',
|
|
493
|
-
files: [
|
|
494
|
-
'charts/bar-race-chart.component.ts',
|
|
495
|
-
'charts/chart.types.ts',
|
|
496
|
-
'charts/chart.utils.ts',
|
|
497
|
-
],
|
|
410
|
+
files: ['charts/bar-race-chart.component.ts', 'charts/chart.types.ts', 'charts/chart.utils.ts'],
|
|
498
411
|
},
|
|
499
412
|
'org-chart': {
|
|
500
413
|
name: 'org-chart',
|
|
501
|
-
files: [
|
|
502
|
-
'charts/org-chart.component.ts',
|
|
503
|
-
'charts/chart.types.ts',
|
|
504
|
-
'charts/chart.utils.ts',
|
|
505
|
-
],
|
|
414
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/org-chart.component.ts'],
|
|
506
415
|
},
|
|
507
416
|
'bento-grid': {
|
|
508
417
|
name: 'bento-grid',
|
|
509
|
-
dependencies: ['
|
|
510
|
-
files: [
|
|
511
|
-
'bento-grid.component.ts',
|
|
512
|
-
],
|
|
418
|
+
dependencies: ['component-outlet', 'context-menu'],
|
|
419
|
+
files: ['bento-grid.component.ts'],
|
|
513
420
|
},
|
|
514
421
|
'page-builder': {
|
|
515
422
|
name: 'page-builder',
|
|
516
|
-
dependencies: [
|
|
517
|
-
|
|
518
|
-
'button',
|
|
519
|
-
'input',
|
|
520
|
-
'label',
|
|
521
|
-
'select',
|
|
522
|
-
'switch',
|
|
523
|
-
'slider',
|
|
524
|
-
'icon'
|
|
525
|
-
],
|
|
526
|
-
files: [
|
|
527
|
-
'page-builder/page-builder.component.ts',
|
|
528
|
-
'page-builder/page-builder.types.ts',
|
|
529
|
-
'page-builder/property-editor.component.ts',
|
|
530
|
-
'page-builder/page-renderer.component.ts'
|
|
531
|
-
],
|
|
423
|
+
dependencies: ['bento-grid', 'icon', 'select', 'switch'],
|
|
424
|
+
files: ['page-builder/page-builder.component.ts', 'page-builder/page-builder.types.ts', 'page-builder/property-editor.component.ts'],
|
|
532
425
|
},
|
|
533
426
|
'component-outlet': {
|
|
534
427
|
name: 'component-outlet',
|
|
535
|
-
files: ['component-outlet.directive.ts'],
|
|
428
|
+
files: ['component-outlet.directive.ts', 'data-table/component-pool.service.ts'],
|
|
536
429
|
},
|
|
537
430
|
'split-button': {
|
|
538
431
|
name: 'split-button',
|
|
539
432
|
files: ['split-button.component.ts'],
|
|
540
|
-
dependencies: ['button'
|
|
433
|
+
dependencies: ['button'],
|
|
541
434
|
},
|
|
542
435
|
// Animations
|
|
543
436
|
'gradient-text': {
|
|
@@ -604,15 +497,26 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
604
497
|
name: 'particles',
|
|
605
498
|
files: ['particles.component.ts'],
|
|
606
499
|
},
|
|
607
|
-
// Kanban
|
|
608
500
|
kanban: {
|
|
609
501
|
name: 'kanban',
|
|
610
|
-
files: ['kanban.
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
'button', 'input', 'textarea', 'label',
|
|
614
|
-
'chip-list', 'autocomplete',
|
|
615
|
-
'dialog', 'alert-dialog', 'context-menu',
|
|
616
|
-
],
|
|
502
|
+
files: ['kanban-locales.ts', 'kanban.component.ts'],
|
|
503
|
+
libFiles: ['shortcut-binding.service.ts'],
|
|
504
|
+
dependencies: ['alert-dialog', 'autocomplete', 'avatar', 'badge', 'button', 'chip-list', 'context-menu', 'dialog', 'input', 'label', 'scroll-area', 'separator', 'textarea'],
|
|
617
505
|
},
|
|
618
|
-
|
|
506
|
+
'shortcut-bindings-dialog': {
|
|
507
|
+
name: 'shortcut-bindings-dialog',
|
|
508
|
+
files: ['shortcut-bindings-dialog.component.ts'],
|
|
509
|
+
libFiles: ['shortcut-binding.service.ts'],
|
|
510
|
+
dependencies: ['accordion', 'badge', 'button', 'dialog', 'scroll-area'],
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
export type ComponentName = keyof typeof registry;
|
|
515
|
+
|
|
516
|
+
export function isComponentName(name: string): name is ComponentName {
|
|
517
|
+
return name in registry;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export function getComponentNames(): ComponentName[] {
|
|
521
|
+
return Object.keys(registry) as ComponentName[];
|
|
522
|
+
}
|
package/src/utils/config.ts
CHANGED
|
@@ -2,8 +2,8 @@ import fs from 'fs-extra';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
export interface Config {
|
|
5
|
-
$schema: string;
|
|
6
5
|
style: 'default';
|
|
6
|
+
registry?: string;
|
|
7
7
|
tailwind: {
|
|
8
8
|
css: string;
|
|
9
9
|
baseColor: 'neutral' | 'slate' | 'stone' | 'gray' | 'zinc';
|
|
@@ -19,7 +19,6 @@ export interface Config {
|
|
|
19
19
|
|
|
20
20
|
export function getDefaultConfig(): Config {
|
|
21
21
|
return {
|
|
22
|
-
$schema: 'https://shadcn-angular.dev/schema.json',
|
|
23
22
|
style: 'default',
|
|
24
23
|
tailwind: {
|
|
25
24
|
css: 'src/styles.scss',
|
|
@@ -35,6 +34,21 @@ export function getDefaultConfig(): Config {
|
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
function validateConfig(data: unknown): data is Config {
|
|
38
|
+
if (!data || typeof data !== 'object') return false;
|
|
39
|
+
const obj = data as Record<string, unknown>;
|
|
40
|
+
|
|
41
|
+
if (!obj['tailwind'] || typeof obj['tailwind'] !== 'object') return false;
|
|
42
|
+
const tw = obj['tailwind'] as Record<string, unknown>;
|
|
43
|
+
if (typeof tw['css'] !== 'string' || typeof tw['baseColor'] !== 'string') return false;
|
|
44
|
+
|
|
45
|
+
if (!obj['aliases'] || typeof obj['aliases'] !== 'object') return false;
|
|
46
|
+
const aliases = obj['aliases'] as Record<string, unknown>;
|
|
47
|
+
if (typeof aliases['components'] !== 'string' || typeof aliases['utils'] !== 'string' || typeof aliases['ui'] !== 'string') return false;
|
|
48
|
+
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
export async function getConfig(cwd: string): Promise<Config | null> {
|
|
39
53
|
const configPath = path.join(cwd, 'components.json');
|
|
40
54
|
|
|
@@ -43,7 +57,12 @@ export async function getConfig(cwd: string): Promise<Config | null> {
|
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
try {
|
|
46
|
-
|
|
60
|
+
const data: unknown = await fs.readJson(configPath);
|
|
61
|
+
if (!validateConfig(data)) {
|
|
62
|
+
console.error('Error: components.json is missing required fields (tailwind.css, tailwind.baseColor, aliases.components, aliases.utils, aliases.ui).');
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return data;
|
|
47
66
|
} catch {
|
|
48
67
|
return null;
|
|
49
68
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
export function validateBranch(branch: string): void {
|
|
9
|
+
if (!/^[\w.\-/]+$/.test(branch)) {
|
|
10
|
+
throw new Error(`Invalid branch name: ${branch}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getDefaultRegistryBaseUrl(branch: string): string {
|
|
15
|
+
validateBranch(branch);
|
|
16
|
+
return `https://raw.githubusercontent.com/gilav21/shadcn-angular/${branch}/packages/components`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getRegistryBaseUrl(branch: string, customRegistry?: string): string {
|
|
20
|
+
const base = customRegistry ?? getDefaultRegistryBaseUrl(branch);
|
|
21
|
+
return `${base}/ui`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getLibRegistryBaseUrl(branch: string, customRegistry?: string): string {
|
|
25
|
+
const base = customRegistry ?? getDefaultRegistryBaseUrl(branch);
|
|
26
|
+
return `${base}/lib`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getLocalComponentsDir(): string | null {
|
|
30
|
+
const localPath = path.resolve(__dirname, '../../../../components/ui');
|
|
31
|
+
return fs.existsSync(localPath) ? localPath : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getLocalLibDir(): string | null {
|
|
35
|
+
const localPath = path.resolve(__dirname, '../../../../components/lib');
|
|
36
|
+
return fs.existsSync(localPath) ? localPath : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveProjectPath(cwd: string, inputPath: string): string {
|
|
40
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
41
|
+
const relative = path.relative(cwd, resolved);
|
|
42
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
43
|
+
throw new Error(`Path must stay inside the project directory: ${inputPath}`);
|
|
44
|
+
}
|
|
45
|
+
return resolved;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function aliasToProjectPath(aliasOrPath: string): string {
|
|
49
|
+
return aliasOrPath.startsWith('@/')
|
|
50
|
+
? path.join('src', aliasOrPath.slice(2))
|
|
51
|
+
: aliasOrPath;
|
|
52
|
+
}
|