@ng-shangjc/cli 1.0.0-beta
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/README.md +216 -0
- package/dist/commands/init.js +280 -0
- package/dist/commands/install.js +332 -0
- package/dist/commands/variants.js +42 -0
- package/dist/index.js +26 -0
- package/dist/utils/variant-configs.js +122 -0
- package/package.json +23 -0
- package/src/commands/init.ts +254 -0
- package/src/commands/install.ts +352 -0
- package/src/commands/variants.ts +45 -0
- package/src/index.ts +31 -0
- package/src/utils/variant-configs.ts +131 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import * as fs from 'fs-extra';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
|
|
5
|
+
export async function initProject() {
|
|
6
|
+
console.log('š Initializing shangjc in your project...');
|
|
7
|
+
|
|
8
|
+
// Check if Angular project
|
|
9
|
+
if (!fs.existsSync('angular.json')) {
|
|
10
|
+
console.error('ā This is not an Angular project.');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Check if shangjc.config.json already exists
|
|
15
|
+
if (fs.existsSync('shangjc.config.json')) {
|
|
16
|
+
console.log('ā ļø shangjc.config.json already exists.');
|
|
17
|
+
const { overwrite } = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'confirm',
|
|
20
|
+
name: 'overwrite',
|
|
21
|
+
message: 'Do you want to overwrite the existing configuration?',
|
|
22
|
+
default: false
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
if (!overwrite) {
|
|
27
|
+
console.log('Initialization cancelled.');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Ask for configuration
|
|
33
|
+
const config = await inquirer.prompt([
|
|
34
|
+
{
|
|
35
|
+
type: 'input',
|
|
36
|
+
name: 'componentsPath',
|
|
37
|
+
message: 'Where would you like to install components?',
|
|
38
|
+
default: 'src/ui/shangjc',
|
|
39
|
+
validate: (input) => {
|
|
40
|
+
if (!input.trim()) return 'Components path is required';
|
|
41
|
+
if (!input.startsWith('src/')) return 'Path should be within src directory';
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'componentType',
|
|
48
|
+
message: 'Which component type do you prefer?',
|
|
49
|
+
choices: [
|
|
50
|
+
{ name: 'Standalone (Recommended)', value: 'standalone' },
|
|
51
|
+
{ name: 'Module-based', value: 'module' }
|
|
52
|
+
],
|
|
53
|
+
default: 'standalone'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'confirm',
|
|
57
|
+
name: 'installTailwind',
|
|
58
|
+
message: 'Do you want to configure Tailwind CSS 4?',
|
|
59
|
+
default: true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'list',
|
|
63
|
+
name: 'theme',
|
|
64
|
+
message: 'Choose your default theme:',
|
|
65
|
+
choices: [
|
|
66
|
+
{ name: 'Default (Light)', value: 'default' },
|
|
67
|
+
{ name: 'Dark', value: 'dark' },
|
|
68
|
+
{ name: 'Both (Light + Dark)', value: 'both' }
|
|
69
|
+
],
|
|
70
|
+
default: 'both',
|
|
71
|
+
when: (answers) => answers.installTailwind
|
|
72
|
+
}
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
// Create components directory
|
|
77
|
+
await fs.ensureDir(config.componentsPath);
|
|
78
|
+
console.log(`ā
Created ${config.componentsPath} directory`);
|
|
79
|
+
|
|
80
|
+
// Create shangjc config
|
|
81
|
+
const configFile = {
|
|
82
|
+
version: '1.0.0',
|
|
83
|
+
componentsPath: config.componentsPath,
|
|
84
|
+
componentType: config.componentType,
|
|
85
|
+
projectType: 'angular',
|
|
86
|
+
theme: {
|
|
87
|
+
current: config.theme || 'default',
|
|
88
|
+
variants: {
|
|
89
|
+
default: {
|
|
90
|
+
primary: 'hsl(var(--primary))',
|
|
91
|
+
secondary: 'hsl(var(--secondary))',
|
|
92
|
+
accent: 'hsl(var(--accent))',
|
|
93
|
+
muted: 'hsl(var(--muted))',
|
|
94
|
+
destructive: 'hsl(var(--destructive))',
|
|
95
|
+
background: 'hsl(var(--background))',
|
|
96
|
+
foreground: 'hsl(var(--foreground))',
|
|
97
|
+
border: 'hsl(var(--border))',
|
|
98
|
+
input: 'hsl(var(--input))',
|
|
99
|
+
ring: 'hsl(var(--ring))'
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
tailwindConfig: config.installTailwind,
|
|
104
|
+
installedComponents: [],
|
|
105
|
+
utilsVersion: '^1.0.0'
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
await fs.writeJson('shangjc.config.json', configFile, { spaces: 2 });
|
|
109
|
+
console.log('ā
Created shangjc.config.json config file');
|
|
110
|
+
|
|
111
|
+
if (config.installTailwind) {
|
|
112
|
+
await setupTailwind();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log('š shangjc initialized successfully!');
|
|
116
|
+
console.log('\nš Next steps:');
|
|
117
|
+
console.log('1. Install a component: npx @ng-shangjc/cli install button');
|
|
118
|
+
console.log('2. Import and use in your components');
|
|
119
|
+
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('ā Initialization failed:', error);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function setupTailwind() {
|
|
127
|
+
// Check if tailwind.config.js exists
|
|
128
|
+
const tailwindConfigPath = 'tailwind.config.js';
|
|
129
|
+
|
|
130
|
+
if (!fs.existsSync(tailwindConfigPath)) {
|
|
131
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
132
|
+
module.exports = {
|
|
133
|
+
content: [
|
|
134
|
+
"./src/**/*.{html,ts}",
|
|
135
|
+
],
|
|
136
|
+
darkMode: 'class',
|
|
137
|
+
theme: {
|
|
138
|
+
extend: {
|
|
139
|
+
colors: {
|
|
140
|
+
primary: {
|
|
141
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
142
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
143
|
+
},
|
|
144
|
+
secondary: {
|
|
145
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
146
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
147
|
+
},
|
|
148
|
+
muted: {
|
|
149
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
150
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
151
|
+
},
|
|
152
|
+
accent: {
|
|
153
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
154
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
155
|
+
},
|
|
156
|
+
destructive: {
|
|
157
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
158
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
159
|
+
},
|
|
160
|
+
border: 'hsl(var(--border))',
|
|
161
|
+
input: 'hsl(var(--input))',
|
|
162
|
+
ring: 'hsl(var(--ring))',
|
|
163
|
+
background: 'hsl(var(--background))',
|
|
164
|
+
foreground: 'hsl(var(--foreground))',
|
|
165
|
+
},
|
|
166
|
+
borderRadius: {
|
|
167
|
+
lg: 'var(--radius)',
|
|
168
|
+
md: 'calc(var(--radius) - 2px)',
|
|
169
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
plugins: [],
|
|
174
|
+
};`;
|
|
175
|
+
|
|
176
|
+
await fs.writeFile(tailwindConfigPath, tailwindConfig);
|
|
177
|
+
console.log('ā
Created tailwind.config.js');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Update global styles with Tailwind 4 @theme directive
|
|
181
|
+
const globalStylesPath = 'src/styles.css';
|
|
182
|
+
|
|
183
|
+
// Check if styles.css exists, if not try other common locations
|
|
184
|
+
let stylesPath = globalStylesPath;
|
|
185
|
+
if (!fs.existsSync(globalStylesPath)) {
|
|
186
|
+
if (fs.existsSync('src/global.css')) {
|
|
187
|
+
stylesPath = 'src/global.css';
|
|
188
|
+
} else if (fs.existsSync('src/app.css')) {
|
|
189
|
+
stylesPath = 'src/app.css';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const globalStyles = `@import 'tailwindcss';
|
|
194
|
+
|
|
195
|
+
@theme {
|
|
196
|
+
--color-primary: 222.2 47.4% 11.2%;
|
|
197
|
+
--color-primary-foreground: 210 40% 98%;
|
|
198
|
+
--color-secondary: 210 40% 96.1%;
|
|
199
|
+
--color-secondary-foreground: 222.2 47.4% 11.2%;
|
|
200
|
+
--color-muted: 210 40% 96.1%;
|
|
201
|
+
--color-muted-foreground: 215.4 16.3% 46.9%;
|
|
202
|
+
--color-accent: 210 40% 96.1%;
|
|
203
|
+
--color-accent-foreground: 222.2 47.4% 11.2%;
|
|
204
|
+
--color-destructive: 0 84.2% 60.2%;
|
|
205
|
+
--color-destructive-foreground: 210 40% 98%;
|
|
206
|
+
--color-border: 214.3 31.8% 91.4%;
|
|
207
|
+
--color-input: 214.3 31.8% 91.4%;
|
|
208
|
+
--color-ring: 222.2 84% 4.9%;
|
|
209
|
+
--color-background: 0 0% 100%;
|
|
210
|
+
--color-foreground: 222.2 84% 4.9%;
|
|
211
|
+
--radius: 0.5rem;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.dark {
|
|
215
|
+
--color-primary: 210 40% 98%;
|
|
216
|
+
--color-primary-foreground: 222.2 47.4% 11.2%;
|
|
217
|
+
--color-secondary: 217.2 32.6% 17.5%;
|
|
218
|
+
--color-secondary-foreground: 210 40% 98%;
|
|
219
|
+
--color-muted: 217.2 32.6% 17.5%;
|
|
220
|
+
--color-muted-foreground: 215 20.2% 65.1%;
|
|
221
|
+
--color-accent: 217.2 32.6% 17.5%;
|
|
222
|
+
--color-accent-foreground: 210 40% 98%;
|
|
223
|
+
--color-destructive: 0 62.8% 30.6%;
|
|
224
|
+
--color-destructive-foreground: 210 40% 98%;
|
|
225
|
+
--color-border: 217.2 32.6% 17.5%;
|
|
226
|
+
--color-input: 217.2 32.6% 17.5%;
|
|
227
|
+
--color-ring: 212.7 26.8% 83.9%;
|
|
228
|
+
--color-background: 222.2 84% 4.9%;
|
|
229
|
+
--color-foreground: 210 40% 98%;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@layer base {
|
|
233
|
+
* {
|
|
234
|
+
@apply border-border;
|
|
235
|
+
}
|
|
236
|
+
body {
|
|
237
|
+
@apply bg-background text-foreground;
|
|
238
|
+
}
|
|
239
|
+
}`;
|
|
240
|
+
|
|
241
|
+
// Append to existing styles or create new file
|
|
242
|
+
if (fs.existsSync(stylesPath)) {
|
|
243
|
+
const existingContent = await fs.readFile(stylesPath, 'utf8');
|
|
244
|
+
if (!existingContent.includes('@import \'tailwindcss\'')) {
|
|
245
|
+
await fs.appendFile(stylesPath, '\n\n' + globalStyles);
|
|
246
|
+
console.log(`ā
Updated ${stylesPath} with Tailwind 4 theme`);
|
|
247
|
+
} else {
|
|
248
|
+
console.log(`ā ļø ${stylesPath} already contains Tailwind imports`);
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
await fs.writeFile(stylesPath, globalStyles);
|
|
252
|
+
console.log(`ā
Created ${stylesPath} with Tailwind 4 theme`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import * as fs from 'fs-extra';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
|
|
6
|
+
interface ShangjcConfig {
|
|
7
|
+
version: string;
|
|
8
|
+
componentsPath: string;
|
|
9
|
+
componentType: 'standalone' | 'module';
|
|
10
|
+
projectType: string;
|
|
11
|
+
theme: {
|
|
12
|
+
current: string;
|
|
13
|
+
variants: Record<string, any>;
|
|
14
|
+
};
|
|
15
|
+
tailwindConfig: boolean;
|
|
16
|
+
installedComponents: string[];
|
|
17
|
+
utilsVersion: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const AVAILABLE_COMPONENTS = [
|
|
21
|
+
'button',
|
|
22
|
+
'input',
|
|
23
|
+
'card',
|
|
24
|
+
'switch',
|
|
25
|
+
'dialog',
|
|
26
|
+
'tooltip',
|
|
27
|
+
'select',
|
|
28
|
+
'checkbox',
|
|
29
|
+
'radio-group',
|
|
30
|
+
'textarea',
|
|
31
|
+
'badge',
|
|
32
|
+
'alert'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const COMPONENT_DEPENDENCIES = {
|
|
36
|
+
button: ['utils'],
|
|
37
|
+
input: ['utils'],
|
|
38
|
+
card: ['utils'],
|
|
39
|
+
switch: ['utils'],
|
|
40
|
+
dialog: ['utils'],
|
|
41
|
+
tooltip: ['utils'],
|
|
42
|
+
select: ['utils'],
|
|
43
|
+
checkbox: ['utils'],
|
|
44
|
+
'radio-group': ['utils'],
|
|
45
|
+
textarea: ['utils'],
|
|
46
|
+
badge: ['utils'],
|
|
47
|
+
alert: ['utils']
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const COMPONENT_FILES = {
|
|
51
|
+
button: [
|
|
52
|
+
'button.component.ts'
|
|
53
|
+
],
|
|
54
|
+
input: [
|
|
55
|
+
'input.component.ts'
|
|
56
|
+
],
|
|
57
|
+
card: [
|
|
58
|
+
'card.component.ts'
|
|
59
|
+
],
|
|
60
|
+
switch: [
|
|
61
|
+
'switch.component.ts'
|
|
62
|
+
],
|
|
63
|
+
dialog: [
|
|
64
|
+
'dialog.component.ts',
|
|
65
|
+
'dialog.service.ts'
|
|
66
|
+
],
|
|
67
|
+
tooltip: [
|
|
68
|
+
'tooltip.component.ts',
|
|
69
|
+
'tooltip.directive.ts'
|
|
70
|
+
],
|
|
71
|
+
select: [
|
|
72
|
+
'select.component.ts'
|
|
73
|
+
],
|
|
74
|
+
checkbox: [
|
|
75
|
+
'checkbox.component.ts'
|
|
76
|
+
],
|
|
77
|
+
'radio-group': [
|
|
78
|
+
'radio-group.component.ts'
|
|
79
|
+
],
|
|
80
|
+
textarea: [
|
|
81
|
+
'textarea.component.ts'
|
|
82
|
+
],
|
|
83
|
+
badge: [
|
|
84
|
+
'badge.component.ts'
|
|
85
|
+
],
|
|
86
|
+
alert: [
|
|
87
|
+
'alert.component.ts'
|
|
88
|
+
]
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export async function installComponent(
|
|
92
|
+
componentName: string,
|
|
93
|
+
options: { path?: string; mode?: string }
|
|
94
|
+
) {
|
|
95
|
+
console.log(`š Installing ${componentName} component...`);
|
|
96
|
+
|
|
97
|
+
// Validate component name
|
|
98
|
+
if (!AVAILABLE_COMPONENTS.includes(componentName)) {
|
|
99
|
+
console.error(`ā Component "${componentName}" not found.`);
|
|
100
|
+
console.log(`Available components: ${AVAILABLE_COMPONENTS.join(', ')}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check if Angular project
|
|
105
|
+
if (!fs.existsSync('angular.json')) {
|
|
106
|
+
console.error('ā This is not an Angular project. Please run this command in an Angular project root.');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check for shangjc.config.json
|
|
111
|
+
const configPath = 'shangjc.config.json';
|
|
112
|
+
if (!fs.existsSync(configPath)) {
|
|
113
|
+
console.log('ā ļø shangjc.config.json not found. Running init first...');
|
|
114
|
+
const { initProject } = await import('./init');
|
|
115
|
+
await initProject();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Load configuration
|
|
119
|
+
const config: ShangjcConfig = await fs.readJson(configPath);
|
|
120
|
+
const componentsPath = options.path || config.componentsPath;
|
|
121
|
+
|
|
122
|
+
// Check if component is already installed
|
|
123
|
+
if (config.installedComponents.includes(componentName)) {
|
|
124
|
+
console.log(`ā ļø ${componentName} is already installed.`);
|
|
125
|
+
const { reinstall } = await inquirer.prompt([
|
|
126
|
+
{
|
|
127
|
+
type: 'confirm',
|
|
128
|
+
name: 'reinstall',
|
|
129
|
+
message: 'Do you want to reinstall it?',
|
|
130
|
+
default: false
|
|
131
|
+
}
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
if (!reinstall) {
|
|
135
|
+
console.log('Installation cancelled.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Show installation summary
|
|
141
|
+
const dependencies = COMPONENT_DEPENDENCIES[componentName as keyof typeof COMPONENT_DEPENDENCIES] || [];
|
|
142
|
+
console.log(`\nš Installation Summary:`);
|
|
143
|
+
console.log(` Component: ${componentName}`);
|
|
144
|
+
console.log(` Path: ${componentsPath}/${componentName}`);
|
|
145
|
+
console.log(` Type: ${config.componentType}`);
|
|
146
|
+
if (dependencies.length > 0) {
|
|
147
|
+
console.log(` Dependencies: ${dependencies.join(', ')}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Confirm installation
|
|
151
|
+
const { confirm } = await inquirer.prompt([
|
|
152
|
+
{
|
|
153
|
+
type: 'confirm',
|
|
154
|
+
name: 'confirm',
|
|
155
|
+
message: 'Proceed with installation?',
|
|
156
|
+
default: true
|
|
157
|
+
}
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
if (!confirm) {
|
|
161
|
+
console.log('Installation cancelled.');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
// Install dependencies first
|
|
167
|
+
if (dependencies.includes('utils')) {
|
|
168
|
+
await installUtils();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Install the component package itself
|
|
172
|
+
await installComponentPackage(componentName);
|
|
173
|
+
|
|
174
|
+
// Create destination directory
|
|
175
|
+
const destDir = path.join(process.cwd(), componentsPath, componentName);
|
|
176
|
+
await fs.ensureDir(destDir);
|
|
177
|
+
|
|
178
|
+
// Get source directory from installed npm package
|
|
179
|
+
const sourceDir = path.join(process.cwd(), 'node_modules', '@ng-shangjc', componentName, 'src', 'lib');
|
|
180
|
+
|
|
181
|
+
// Copy component files
|
|
182
|
+
const files = COMPONENT_FILES[componentName as keyof typeof COMPONENT_FILES];
|
|
183
|
+
|
|
184
|
+
for (const file of files) {
|
|
185
|
+
const sourcePath = path.join(sourceDir, file);
|
|
186
|
+
const destPath = path.join(destDir, file);
|
|
187
|
+
|
|
188
|
+
if (await fs.pathExists(sourcePath)) {
|
|
189
|
+
await fs.copy(sourcePath, destPath);
|
|
190
|
+
console.log(`ā
Copied ${file}`);
|
|
191
|
+
} else {
|
|
192
|
+
console.warn(`ā ļø Source file not found: ${sourcePath}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Create index file
|
|
197
|
+
const indexContent = generateIndexFile(componentName, files, config.componentType);
|
|
198
|
+
await fs.writeFile(path.join(destDir, 'index.ts'), indexContent);
|
|
199
|
+
console.log(`ā
Created index.ts`);
|
|
200
|
+
|
|
201
|
+
// Copy README
|
|
202
|
+
const readmePath = path.join(process.cwd(), 'node_modules', '@ng-shangjc', componentName, 'README.md');
|
|
203
|
+
if (await fs.pathExists(readmePath)) {
|
|
204
|
+
await fs.copy(readmePath, path.join(destDir, 'README.md'));
|
|
205
|
+
console.log(`ā
Copied README.md`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Update configuration
|
|
209
|
+
if (!config.installedComponents.includes(componentName)) {
|
|
210
|
+
config.installedComponents.push(componentName);
|
|
211
|
+
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
212
|
+
console.log(`ā
Updated shangjc.config.json`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(`š Successfully installed ${componentName} component!`);
|
|
216
|
+
console.log(`\nš Files installed to: ${destDir}`);
|
|
217
|
+
console.log(`\nš Usage:`);
|
|
218
|
+
console.log(`import { ${getComponentClassName(componentName)} } from './${componentsPath}/${componentName}';`);
|
|
219
|
+
|
|
220
|
+
} catch (error) {
|
|
221
|
+
console.error('ā Installation failed:', error);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function installUtils() {
|
|
227
|
+
console.log('š¦ Installing utils dependency...');
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
// Check if utils is already installed in node_modules
|
|
231
|
+
const utilsPath = path.join(process.cwd(), 'node_modules', '@ng-shangjc', 'utils');
|
|
232
|
+
|
|
233
|
+
if (!fs.existsSync(utilsPath)) {
|
|
234
|
+
console.log('Installing @ng-shangjc/utils...');
|
|
235
|
+
execSync('npm install --save-dev @ng-shangjc/utils', { stdio: 'inherit' });
|
|
236
|
+
} else {
|
|
237
|
+
console.log('ā
@ng-shangjc/utils already installed');
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error('ā Failed to install utils:', error);
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function installComponentPackage(componentName: string) {
|
|
246
|
+
console.log(`š¦ Installing ${componentName} package...`);
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
// Check if component is already installed in node_modules
|
|
250
|
+
const componentPath = path.join(process.cwd(), 'node_modules', '@ng-shangjc', componentName);
|
|
251
|
+
|
|
252
|
+
if (!fs.existsSync(componentPath)) {
|
|
253
|
+
console.log(`Installing @ng-shangjc/${componentName}...`);
|
|
254
|
+
execSync(`npm install --save-dev @ng-shangjc/${componentName}`, { stdio: 'inherit' });
|
|
255
|
+
} else {
|
|
256
|
+
console.log(`ā
@ng-shangjc/${componentName} already installed`);
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(`ā Failed to install ${componentName} package:`, error);
|
|
260
|
+
console.log(`š Attempting to download files directly...`);
|
|
261
|
+
|
|
262
|
+
// Fallback: try to download files directly from npm registry
|
|
263
|
+
try {
|
|
264
|
+
await downloadComponentFiles(componentName);
|
|
265
|
+
console.log(`ā
Successfully downloaded ${componentName} files directly`);
|
|
266
|
+
} catch (downloadError) {
|
|
267
|
+
console.error(`ā Failed to download ${componentName} files:`, downloadError);
|
|
268
|
+
throw new Error(`Failed to install ${componentName}: Package installation and direct download both failed`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function downloadComponentFiles(componentName: string) {
|
|
274
|
+
const https = require('https');
|
|
275
|
+
const tar = require('tar');
|
|
276
|
+
|
|
277
|
+
return new Promise<void>((resolve, reject) => {
|
|
278
|
+
const packageUrl = `https://registry.npmjs.org/@ng-shangjc/${componentName}/-/${componentName}-1.0.0.tgz`;
|
|
279
|
+
const tempDir = path.join(process.cwd(), '.ng-shangjc-temp');
|
|
280
|
+
|
|
281
|
+
// Ensure temp directory exists
|
|
282
|
+
fs.ensureDirSync(tempDir);
|
|
283
|
+
|
|
284
|
+
const file = fs.createWriteStream(path.join(tempDir, `${componentName}.tgz`));
|
|
285
|
+
|
|
286
|
+
https.get(packageUrl, (response: any) => {
|
|
287
|
+
if (response.statusCode !== 200) {
|
|
288
|
+
reject(new Error(`Failed to download package: ${response.statusCode}`));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
response.pipe(file);
|
|
293
|
+
|
|
294
|
+
file.on('finish', () => {
|
|
295
|
+
file.close();
|
|
296
|
+
|
|
297
|
+
// Extract the tarball
|
|
298
|
+
fs.createReadStream(path.join(tempDir, `${componentName}.tgz`))
|
|
299
|
+
.pipe(tar.extract({
|
|
300
|
+
cwd: tempDir,
|
|
301
|
+
strip: 1 // Remove the package folder
|
|
302
|
+
}))
|
|
303
|
+
.on('finish', () => {
|
|
304
|
+
// Copy the extracted files to node_modules structure
|
|
305
|
+
const sourceDir = path.join(tempDir, 'src', 'lib');
|
|
306
|
+
const targetDir = path.join(process.cwd(), 'node_modules', '@ng-shangjc', componentName, 'src', 'lib');
|
|
307
|
+
|
|
308
|
+
fs.ensureDirSync(path.dirname(targetDir));
|
|
309
|
+
|
|
310
|
+
if (fs.existsSync(sourceDir)) {
|
|
311
|
+
fs.copySync(sourceDir, targetDir);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Copy README if exists
|
|
315
|
+
const readmeSource = path.join(tempDir, 'README.md');
|
|
316
|
+
const readmeTarget = path.join(process.cwd(), 'node_modules', '@ng-shangjc', componentName, 'README.md');
|
|
317
|
+
|
|
318
|
+
if (fs.existsSync(readmeSource)) {
|
|
319
|
+
fs.copySync(readmeSource, readmeTarget);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Clean up temp files
|
|
323
|
+
fs.removeSync(tempDir);
|
|
324
|
+
|
|
325
|
+
resolve();
|
|
326
|
+
})
|
|
327
|
+
.on('error', reject);
|
|
328
|
+
});
|
|
329
|
+
}).on('error', reject);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function generateIndexFile(componentName: string, files: string[], mode: string): string {
|
|
334
|
+
const exports = files
|
|
335
|
+
.filter(file => file.endsWith('.ts'))
|
|
336
|
+
.map(file => {
|
|
337
|
+
const name = file.replace('.ts', '');
|
|
338
|
+
return `export * from './${name}';`;
|
|
339
|
+
})
|
|
340
|
+
.join('\n');
|
|
341
|
+
|
|
342
|
+
return `// Generated by ng-shangjc CLI
|
|
343
|
+
// Component: ${componentName}
|
|
344
|
+
// Mode: ${mode}
|
|
345
|
+
|
|
346
|
+
${exports}
|
|
347
|
+
`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function getComponentClassName(componentName: string): string {
|
|
351
|
+
return componentName.charAt(0).toUpperCase() + componentName.slice(1) + 'Component';
|
|
352
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { getComponentVariantConfig, getAllVariantConfigs } from '../utils/variant-configs';
|
|
2
|
+
|
|
3
|
+
export async function showVariants(componentName?: string) {
|
|
4
|
+
if (componentName) {
|
|
5
|
+
// Show variants for specific component
|
|
6
|
+
const config = getComponentVariantConfig(componentName);
|
|
7
|
+
|
|
8
|
+
if (!config) {
|
|
9
|
+
console.log(`ā No variant configuration found for component "${componentName}"`);
|
|
10
|
+
console.log('\nAvailable components with variants:');
|
|
11
|
+
const allConfigs = getAllVariantConfigs();
|
|
12
|
+
allConfigs.forEach(config => {
|
|
13
|
+
console.log(` - ${config.component}`);
|
|
14
|
+
});
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(`\nšØ Variant configurations for ${config.component}:`);
|
|
19
|
+
console.log(` Default variant: ${config.defaultVariant}\n`);
|
|
20
|
+
|
|
21
|
+
config.variants.forEach(variant => {
|
|
22
|
+
console.log(` ⢠${variant.name}${variant.name === config.defaultVariant ? ' (default)' : ''}`);
|
|
23
|
+
if (variant.description) {
|
|
24
|
+
console.log(` ${variant.description}`);
|
|
25
|
+
}
|
|
26
|
+
console.log(` Classes: ${variant.classes}\n`);
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
// Show all component variants
|
|
30
|
+
const allConfigs = getAllVariantConfigs();
|
|
31
|
+
|
|
32
|
+
if (allConfigs.length === 0) {
|
|
33
|
+
console.log('ā No variant configurations found');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('\nšØ All component variant configurations:\n');
|
|
38
|
+
|
|
39
|
+
allConfigs.forEach(config => {
|
|
40
|
+
console.log(`š¦ ${config.component}:`);
|
|
41
|
+
console.log(` Variants: ${config.variants.map(v => v.name).join(', ')}`);
|
|
42
|
+
console.log(` Default: ${config.defaultVariant}\n`);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { installComponent } from './commands/install';
|
|
5
|
+
import { initProject } from './commands/init';
|
|
6
|
+
import { showVariants } from './commands/variants';
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('ng-shangjc')
|
|
12
|
+
.description('CLI for ng-shangjc UI component library')
|
|
13
|
+
.version('1.0.0');
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.command('install <component>')
|
|
17
|
+
.description('Install a component into your project')
|
|
18
|
+
.option('-p, --path <path>', 'Override installation path from config')
|
|
19
|
+
.action(installComponent);
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command('init')
|
|
23
|
+
.description('Initialize shangjc in your project')
|
|
24
|
+
.action(initProject);
|
|
25
|
+
|
|
26
|
+
program
|
|
27
|
+
.command('variants [component]')
|
|
28
|
+
.description('Show variant configurations for components')
|
|
29
|
+
.action(showVariants);
|
|
30
|
+
|
|
31
|
+
program.parse();
|