svger-cli 2.0.2 → 2.0.4
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/.svgerconfig.example.json +119 -0
- package/CHANGELOG.md +64 -0
- package/DEVELOPMENT.md +353 -0
- package/README.md +430 -209
- package/SECURITY.md +69 -0
- package/dist/builder.js +16 -16
- package/dist/clean.js +2 -2
- package/dist/cli.js +38 -38
- package/dist/config.js +95 -12
- package/dist/core/error-handler.js +12 -9
- package/dist/core/framework-templates.js +5 -3
- package/dist/core/performance-engine.js +9 -8
- package/dist/core/plugin-manager.js +7 -5
- package/dist/core/style-compiler.js +17 -15
- package/dist/core/template-manager.js +14 -14
- package/dist/index.d.ts +8 -6
- package/dist/index.js +5 -5
- package/dist/lock.js +7 -7
- package/dist/processors/svg-processor.d.ts +9 -3
- package/dist/processors/svg-processor.js +56 -18
- package/dist/services/config.js +72 -20
- package/dist/services/file-watcher.js +3 -3
- package/dist/services/svg-service.js +34 -30
- package/dist/templates/ComponentTemplate.js +25 -25
- package/dist/types/index.d.ts +77 -19
- package/dist/utils/native.d.ts +32 -1
- package/dist/utils/native.js +47 -8
- package/dist/watch.d.ts +1 -1
- package/dist/watch.js +14 -14
- package/docs/ADR-SVG-INTRGRATION-METHODS-001.adr.md +157 -0
- package/docs/ADR-SVG-INTRGRATION-METHODS-002.adr.md +550 -0
- package/docs/FRAMEWORK-GUIDE.md +768 -0
- package/docs/IMPLEMENTATION-SUMMARY.md +376 -0
- package/docs/TDR-SVG-INTRGRATION-METHODS-001.tdr.md +115 -0
- package/package.json +155 -14
package/dist/services/config.js
CHANGED
|
@@ -20,40 +20,90 @@ export class ConfigService {
|
|
|
20
20
|
*/
|
|
21
21
|
getDefaultConfig() {
|
|
22
22
|
return {
|
|
23
|
+
// Source & Output
|
|
23
24
|
source: './src/assets/svg',
|
|
24
25
|
output: './src/components/icons',
|
|
26
|
+
// Framework Configuration
|
|
25
27
|
framework: 'react',
|
|
26
28
|
typescript: true,
|
|
29
|
+
componentType: 'functional',
|
|
30
|
+
// Processing Options
|
|
27
31
|
watch: false,
|
|
32
|
+
parallel: true,
|
|
33
|
+
batchSize: 10,
|
|
34
|
+
maxConcurrency: 4,
|
|
35
|
+
cache: true,
|
|
36
|
+
// Default Properties
|
|
28
37
|
defaultWidth: 24,
|
|
29
38
|
defaultHeight: 24,
|
|
30
39
|
defaultFill: 'currentColor',
|
|
31
|
-
|
|
40
|
+
defaultStroke: 'none',
|
|
41
|
+
defaultStrokeWidth: 1,
|
|
42
|
+
// Styling Configuration
|
|
32
43
|
styleRules: {
|
|
33
44
|
fill: 'inherit',
|
|
34
45
|
stroke: 'none',
|
|
35
46
|
},
|
|
47
|
+
responsive: {
|
|
48
|
+
breakpoints: ['sm', 'md', 'lg', 'xl'],
|
|
49
|
+
values: {
|
|
50
|
+
width: ['16px', '20px', '24px', '32px'],
|
|
51
|
+
height: ['16px', '20px', '24px', '32px'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
theme: {
|
|
55
|
+
mode: 'auto',
|
|
56
|
+
variables: {
|
|
57
|
+
primary: 'currentColor',
|
|
58
|
+
secondary: '#6b7280',
|
|
59
|
+
accent: '#3b82f6',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
animations: [],
|
|
63
|
+
// Advanced Options
|
|
36
64
|
plugins: [],
|
|
37
|
-
|
|
38
|
-
|
|
65
|
+
exclude: [],
|
|
66
|
+
include: [],
|
|
67
|
+
// Error Handling
|
|
68
|
+
errorHandling: {
|
|
69
|
+
strategy: 'continue',
|
|
70
|
+
maxRetries: 3,
|
|
71
|
+
timeout: 30000,
|
|
72
|
+
},
|
|
73
|
+
// Performance Settings
|
|
74
|
+
performance: {
|
|
75
|
+
optimization: 'balanced',
|
|
76
|
+
memoryLimit: 512,
|
|
77
|
+
cacheTimeout: 3600000,
|
|
78
|
+
},
|
|
79
|
+
// Output Customization
|
|
80
|
+
outputConfig: {
|
|
81
|
+
naming: 'pascal',
|
|
82
|
+
extension: 'tsx',
|
|
83
|
+
directory: './src/components/icons',
|
|
39
84
|
},
|
|
40
|
-
|
|
85
|
+
// Framework-specific configurations
|
|
86
|
+
react: {
|
|
87
|
+
componentType: 'functional',
|
|
41
88
|
forwardRef: true,
|
|
42
89
|
memo: false,
|
|
43
|
-
|
|
44
|
-
|
|
90
|
+
propsInterface: 'SVGProps',
|
|
91
|
+
styledComponents: false,
|
|
92
|
+
cssModules: false,
|
|
45
93
|
},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
94
|
+
vue: {
|
|
95
|
+
api: 'composition',
|
|
96
|
+
setup: true,
|
|
97
|
+
typescript: true,
|
|
98
|
+
scoped: true,
|
|
99
|
+
cssVariables: true,
|
|
100
|
+
},
|
|
101
|
+
angular: {
|
|
102
|
+
standalone: true,
|
|
103
|
+
signals: true,
|
|
104
|
+
changeDetection: 'OnPush',
|
|
105
|
+
encapsulation: 'Emulated',
|
|
50
106
|
},
|
|
51
|
-
performance: {
|
|
52
|
-
batchSize: 10,
|
|
53
|
-
parallel: true,
|
|
54
|
-
timeout: 30000,
|
|
55
|
-
enableCache: true
|
|
56
|
-
}
|
|
57
107
|
};
|
|
58
108
|
}
|
|
59
109
|
/**
|
|
@@ -79,7 +129,7 @@ export class ConfigService {
|
|
|
79
129
|
// Merge with defaults to ensure all required properties exist
|
|
80
130
|
this.cachedConfig = {
|
|
81
131
|
...this.getDefaultConfig(),
|
|
82
|
-
...configData
|
|
132
|
+
...configData,
|
|
83
133
|
};
|
|
84
134
|
logger.debug('Configuration loaded successfully');
|
|
85
135
|
return this.cachedConfig;
|
|
@@ -165,7 +215,8 @@ export class ConfigService {
|
|
|
165
215
|
// Required string fields
|
|
166
216
|
const requiredStringFields = ['source', 'output', 'defaultFill'];
|
|
167
217
|
for (const field of requiredStringFields) {
|
|
168
|
-
if (!configToValidate[field] ||
|
|
218
|
+
if (!configToValidate[field] ||
|
|
219
|
+
typeof configToValidate[field] !== 'string') {
|
|
169
220
|
errors.push(`${field} must be a non-empty string`);
|
|
170
221
|
}
|
|
171
222
|
}
|
|
@@ -182,12 +233,13 @@ export class ConfigService {
|
|
|
182
233
|
errors.push('exclude must be an array');
|
|
183
234
|
}
|
|
184
235
|
// Validate styleRules object
|
|
185
|
-
if (configToValidate.styleRules &&
|
|
236
|
+
if (configToValidate.styleRules &&
|
|
237
|
+
typeof configToValidate.styleRules !== 'object') {
|
|
186
238
|
errors.push('styleRules must be an object');
|
|
187
239
|
}
|
|
188
240
|
return {
|
|
189
241
|
valid: errors.length === 0,
|
|
190
|
-
errors
|
|
242
|
+
errors,
|
|
191
243
|
};
|
|
192
244
|
}
|
|
193
245
|
/**
|
|
@@ -30,7 +30,7 @@ export class FileWatcherService {
|
|
|
30
30
|
try {
|
|
31
31
|
const watcher = fs.watch(resolvedPath, {
|
|
32
32
|
persistent: true,
|
|
33
|
-
recursive: false
|
|
33
|
+
recursive: false,
|
|
34
34
|
}, (eventType, filename) => {
|
|
35
35
|
if (filename) {
|
|
36
36
|
this.handleFileEvent(watchId, eventType, path.join(resolvedPath, filename));
|
|
@@ -83,7 +83,7 @@ export class FileWatcherService {
|
|
|
83
83
|
const event = {
|
|
84
84
|
type: actualEventType,
|
|
85
85
|
filePath,
|
|
86
|
-
timestamp: Date.now()
|
|
86
|
+
timestamp: Date.now(),
|
|
87
87
|
};
|
|
88
88
|
logger.debug(`File event: ${actualEventType} - ${path.basename(filePath)}`);
|
|
89
89
|
// Emit event to registered handlers
|
|
@@ -160,7 +160,7 @@ export class FileWatcherService {
|
|
|
160
160
|
return {
|
|
161
161
|
activeWatchers: this.watchers.size,
|
|
162
162
|
pendingEvents: this.debounceTimers.size,
|
|
163
|
-
totalHandlers
|
|
163
|
+
totalHandlers,
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
@@ -41,9 +41,15 @@ export class SVGService {
|
|
|
41
41
|
...config,
|
|
42
42
|
...(options.config || {}),
|
|
43
43
|
// Support direct properties on options for CLI convenience
|
|
44
|
-
...options.framework && {
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
...(options.framework && {
|
|
45
|
+
framework: options.framework,
|
|
46
|
+
}),
|
|
47
|
+
...(options.typescript !== undefined && {
|
|
48
|
+
typescript: options.typescript,
|
|
49
|
+
}),
|
|
50
|
+
...(options.frameworkOptions && {
|
|
51
|
+
frameworkOptions: options.frameworkOptions,
|
|
52
|
+
}),
|
|
47
53
|
};
|
|
48
54
|
// Read all SVG files
|
|
49
55
|
const files = await FileSystem.readDir(srcDir);
|
|
@@ -70,12 +76,13 @@ export class SVGService {
|
|
|
70
76
|
defaultWidth: mergedConfig.defaultWidth,
|
|
71
77
|
defaultHeight: mergedConfig.defaultHeight,
|
|
72
78
|
defaultFill: mergedConfig.defaultFill,
|
|
73
|
-
|
|
79
|
+
namingConvention: mergedConfig.output?.naming || 'pascal',
|
|
80
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([, v]) => v !== undefined)),
|
|
74
81
|
});
|
|
75
82
|
results.push({
|
|
76
83
|
success: processingResult.success,
|
|
77
84
|
file,
|
|
78
|
-
error: processingResult.error
|
|
85
|
+
error: processingResult.error,
|
|
79
86
|
});
|
|
80
87
|
}
|
|
81
88
|
catch (error) {
|
|
@@ -83,7 +90,7 @@ export class SVGService {
|
|
|
83
90
|
results.push({
|
|
84
91
|
success: false,
|
|
85
92
|
file,
|
|
86
|
-
error: error
|
|
93
|
+
error: error,
|
|
87
94
|
});
|
|
88
95
|
}
|
|
89
96
|
}
|
|
@@ -93,13 +100,15 @@ export class SVGService {
|
|
|
93
100
|
logger.info(`Build complete: ${successful} successful, ${failed} failed`);
|
|
94
101
|
if (failed > 0) {
|
|
95
102
|
logger.warn('Some files failed to process:');
|
|
96
|
-
results
|
|
103
|
+
results
|
|
104
|
+
.filter(r => !r.success)
|
|
105
|
+
.forEach(r => {
|
|
97
106
|
logger.warn(` - ${r.file}: ${r.error?.message}`);
|
|
98
107
|
});
|
|
99
108
|
}
|
|
100
109
|
// Generate index.ts file with all component exports
|
|
101
110
|
if (successful > 0) {
|
|
102
|
-
await this.generateIndexFile(outDir, results.filter(r => r.success).map(r => r.file));
|
|
111
|
+
await this.generateIndexFile(outDir, results.filter(r => r.success).map(r => r.file), mergedConfig);
|
|
103
112
|
}
|
|
104
113
|
}
|
|
105
114
|
/**
|
|
@@ -126,7 +135,7 @@ export class SVGService {
|
|
|
126
135
|
defaultWidth: mergedConfig.defaultWidth,
|
|
127
136
|
defaultHeight: mergedConfig.defaultHeight,
|
|
128
137
|
defaultFill: mergedConfig.defaultFill,
|
|
129
|
-
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([
|
|
138
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([, v]) => v !== undefined)),
|
|
130
139
|
});
|
|
131
140
|
if (!result.success) {
|
|
132
141
|
throw result.error || new Error('Failed to generate component');
|
|
@@ -194,7 +203,7 @@ export class SVGService {
|
|
|
194
203
|
defaultWidth: mergedConfig.defaultWidth,
|
|
195
204
|
defaultHeight: mergedConfig.defaultHeight,
|
|
196
205
|
defaultFill: mergedConfig.defaultFill,
|
|
197
|
-
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([
|
|
206
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([, v]) => v !== undefined)),
|
|
198
207
|
});
|
|
199
208
|
}
|
|
200
209
|
catch (error) {
|
|
@@ -204,9 +213,10 @@ export class SVGService {
|
|
|
204
213
|
/**
|
|
205
214
|
* Handle file removal in watch mode
|
|
206
215
|
*/
|
|
207
|
-
async handleFileRemoval(filePath, outDir) {
|
|
216
|
+
async handleFileRemoval(filePath, outDir, config) {
|
|
208
217
|
try {
|
|
209
|
-
const
|
|
218
|
+
const namingConvention = config?.output?.naming || 'pascal';
|
|
219
|
+
const componentName = svgProcessor.generateComponentName(path.basename(filePath), namingConvention);
|
|
210
220
|
const componentPath = path.join(outDir, `${componentName}.tsx`);
|
|
211
221
|
if (await FileSystem.exists(componentPath)) {
|
|
212
222
|
await FileSystem.unlink(componentPath);
|
|
@@ -248,11 +258,12 @@ export class SVGService {
|
|
|
248
258
|
/**
|
|
249
259
|
* Generate index.ts file with all component exports
|
|
250
260
|
*/
|
|
251
|
-
async generateIndexFile(outDir, svgFiles) {
|
|
261
|
+
async generateIndexFile(outDir, svgFiles, config) {
|
|
252
262
|
try {
|
|
263
|
+
const namingConvention = config?.output?.naming || 'pascal';
|
|
253
264
|
const componentNames = svgFiles.map(file => {
|
|
254
265
|
const baseName = path.basename(file, '.svg');
|
|
255
|
-
return svgProcessor.generateComponentName(baseName);
|
|
266
|
+
return svgProcessor.generateComponentName(baseName, namingConvention);
|
|
256
267
|
});
|
|
257
268
|
const indexContent = this.generateIndexContent(componentNames);
|
|
258
269
|
const indexPath = path.join(outDir, 'index.ts');
|
|
@@ -267,18 +278,9 @@ export class SVGService {
|
|
|
267
278
|
* Generate the content for index.ts file
|
|
268
279
|
*/
|
|
269
280
|
generateIndexContent(componentNames) {
|
|
270
|
-
const imports = componentNames
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
export {
|
|
274
|
-
${componentNames.map(name => ` ${name},`).join('\n')}
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
// Re-export for convenience
|
|
278
|
-
export default {
|
|
279
|
-
${componentNames.map(name => ` ${name},`).join('\n')}
|
|
280
|
-
};
|
|
281
|
-
`;
|
|
281
|
+
const imports = componentNames
|
|
282
|
+
.map(name => `export { default as ${name} } from './${name}';`)
|
|
283
|
+
.join('\n');
|
|
282
284
|
return `/**
|
|
283
285
|
* SVG Components Index
|
|
284
286
|
* Generated by svger-cli
|
|
@@ -288,10 +290,10 @@ ${componentNames.map(name => ` ${name},`).join('\n')}
|
|
|
288
290
|
*
|
|
289
291
|
* Import all components:
|
|
290
292
|
* import * as Icons from './components';
|
|
291
|
-
* import Icons from './components'; // default export
|
|
292
293
|
*/
|
|
293
294
|
|
|
294
|
-
${imports}
|
|
295
|
+
${imports}
|
|
296
|
+
`;
|
|
295
297
|
}
|
|
296
298
|
/**
|
|
297
299
|
* Get service statistics
|
|
@@ -300,7 +302,7 @@ ${imports}${exportAll}`;
|
|
|
300
302
|
return {
|
|
301
303
|
activeWatchers: this.activeWatchers.size,
|
|
302
304
|
processingQueue: svgProcessor.getProcessingStats(),
|
|
303
|
-
watcherStats: fileWatcher.getWatchStats()
|
|
305
|
+
watcherStats: fileWatcher.getWatchStats(),
|
|
304
306
|
};
|
|
305
307
|
}
|
|
306
308
|
/**
|
|
@@ -346,7 +348,9 @@ export class LockService {
|
|
|
346
348
|
}
|
|
347
349
|
writeLockFile(locks) {
|
|
348
350
|
try {
|
|
349
|
-
FileSystem.writeJSONSync(this.getLockFilePath(), Array.from(locks), {
|
|
351
|
+
FileSystem.writeJSONSync(this.getLockFilePath(), Array.from(locks), {
|
|
352
|
+
spaces: 2,
|
|
353
|
+
});
|
|
350
354
|
this.cachedLocks = locks;
|
|
351
355
|
}
|
|
352
356
|
catch (error) {
|
|
@@ -13,32 +13,32 @@
|
|
|
13
13
|
* @param [options.defaultFill="currentColor"] - The default fill color for the SVG.
|
|
14
14
|
* @returns A string containing the complete TypeScript code for the React SVG component.
|
|
15
15
|
*/
|
|
16
|
-
export function reactTemplate({ componentName, svgContent, defaultWidth = 24, defaultHeight = 24, defaultFill =
|
|
16
|
+
export function reactTemplate({ componentName, svgContent, defaultWidth = 24, defaultHeight = 24, defaultFill = 'currentColor', }) {
|
|
17
17
|
const cleaned = svgContent
|
|
18
|
-
.replace(/<\?xml.*?\?>/g,
|
|
19
|
-
.replace(/<!DOCTYPE.*?>/g,
|
|
20
|
-
.replace(/\r?\n|\r/g,
|
|
21
|
-
.replace(/\s{2,}/g,
|
|
22
|
-
.replace(/style="[^"]*"/g,
|
|
23
|
-
.replace(/\s+xmlns(:xlink)?="[^"]*"/g,
|
|
18
|
+
.replace(/<\?xml.*?\?>/g, '')
|
|
19
|
+
.replace(/<!DOCTYPE.*?>/g, '')
|
|
20
|
+
.replace(/\r?\n|\r/g, '')
|
|
21
|
+
.replace(/\s{2,}/g, ' ')
|
|
22
|
+
.replace(/style="[^"]*"/g, '')
|
|
23
|
+
.replace(/\s+xmlns(:xlink)?="[^"]*"/g, '')
|
|
24
24
|
.trim()
|
|
25
|
-
.replace(/^.*?<svg[^>]*>(.*?)<\/svg>.*$/i,
|
|
26
|
-
return `import type { SVGProps } from "react";
|
|
27
|
-
const Svg${componentName} = (props: SVGProps<SVGSVGElement>) => (
|
|
28
|
-
<svg
|
|
29
|
-
viewBox="0 0 ${defaultWidth} ${defaultHeight}"
|
|
30
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
-
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
32
|
-
width={props.width || ${defaultWidth}}
|
|
33
|
-
height={props.height || ${defaultHeight}}
|
|
34
|
-
fill={props.fill || "${defaultFill}"}
|
|
35
|
-
stroke={props.stroke || "none"}
|
|
36
|
-
className={props.className}
|
|
37
|
-
{...props}
|
|
38
|
-
>
|
|
39
|
-
${cleaned}
|
|
40
|
-
</svg>
|
|
41
|
-
);
|
|
42
|
-
export default Svg${componentName};
|
|
25
|
+
.replace(/^.*?<svg[^>]*>(.*?)<\/svg>.*$/i, '$1');
|
|
26
|
+
return `import type { SVGProps } from "react";
|
|
27
|
+
const Svg${componentName} = (props: SVGProps<SVGSVGElement>) => (
|
|
28
|
+
<svg
|
|
29
|
+
viewBox="0 0 ${defaultWidth} ${defaultHeight}"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
32
|
+
width={props.width || ${defaultWidth}}
|
|
33
|
+
height={props.height || ${defaultHeight}}
|
|
34
|
+
fill={props.fill || "${defaultFill}"}
|
|
35
|
+
stroke={props.stroke || "none"}
|
|
36
|
+
className={props.className}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
${cleaned}
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
export default Svg${componentName};
|
|
43
43
|
`;
|
|
44
44
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,35 +2,92 @@
|
|
|
2
2
|
* Type definitions for svger-cli
|
|
3
3
|
*/
|
|
4
4
|
export type FrameworkType = 'react' | 'vue' | 'svelte' | 'angular' | 'solid' | 'preact' | 'lit' | 'vanilla';
|
|
5
|
+
export type NamingConvention = 'kebab' | 'pascal' | 'camel';
|
|
6
|
+
export type ComponentType = 'functional' | 'class' | 'arrow';
|
|
7
|
+
export type ErrorHandlingStrategy = 'continue' | 'stop' | 'retry';
|
|
8
|
+
export type PerformanceOptimization = 'fast' | 'balanced' | 'maximum';
|
|
9
|
+
export type ThemeMode = 'light' | 'dark' | 'auto';
|
|
10
|
+
export type ChangeDetectionStrategy = 'Default' | 'OnPush';
|
|
11
|
+
export type ViewEncapsulation = 'Emulated' | 'None' | 'ShadowDom';
|
|
12
|
+
export interface OutputConfig {
|
|
13
|
+
naming?: NamingConvention;
|
|
14
|
+
extension?: string;
|
|
15
|
+
directory?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ResponsiveConfig {
|
|
18
|
+
breakpoints: string[];
|
|
19
|
+
values: {
|
|
20
|
+
[property: string]: string[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface ThemeConfig {
|
|
24
|
+
mode: ThemeMode;
|
|
25
|
+
variables: {
|
|
26
|
+
[name: string]: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface ErrorHandlingConfig {
|
|
30
|
+
strategy: ErrorHandlingStrategy;
|
|
31
|
+
maxRetries: number;
|
|
32
|
+
timeout: number;
|
|
33
|
+
}
|
|
34
|
+
export interface PerformanceConfig {
|
|
35
|
+
optimization: PerformanceOptimization;
|
|
36
|
+
memoryLimit: number;
|
|
37
|
+
cacheTimeout: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ReactConfig {
|
|
40
|
+
componentType?: ComponentType;
|
|
41
|
+
forwardRef?: boolean;
|
|
42
|
+
memo?: boolean;
|
|
43
|
+
propsInterface?: string;
|
|
44
|
+
styledComponents?: boolean;
|
|
45
|
+
cssModules?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface VueConfig {
|
|
48
|
+
api?: 'composition' | 'options';
|
|
49
|
+
setup?: boolean;
|
|
50
|
+
typescript?: boolean;
|
|
51
|
+
scoped?: boolean;
|
|
52
|
+
cssVariables?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface AngularConfig {
|
|
55
|
+
standalone?: boolean;
|
|
56
|
+
signals?: boolean;
|
|
57
|
+
changeDetection?: ChangeDetectionStrategy;
|
|
58
|
+
encapsulation?: ViewEncapsulation;
|
|
59
|
+
}
|
|
5
60
|
export interface SVGConfig {
|
|
6
61
|
source: string;
|
|
7
62
|
output: string;
|
|
8
|
-
watch: boolean;
|
|
9
63
|
framework: FrameworkType;
|
|
10
64
|
typescript: boolean;
|
|
65
|
+
componentType?: ComponentType;
|
|
66
|
+
watch: boolean;
|
|
67
|
+
parallel: boolean;
|
|
68
|
+
batchSize: number;
|
|
69
|
+
maxConcurrency: number;
|
|
70
|
+
cache: boolean;
|
|
11
71
|
defaultWidth: number;
|
|
12
72
|
defaultHeight: number;
|
|
13
73
|
defaultFill: string;
|
|
14
|
-
|
|
74
|
+
defaultStroke?: string;
|
|
75
|
+
defaultStrokeWidth?: number;
|
|
15
76
|
styleRules: {
|
|
16
|
-
|
|
17
|
-
stroke?: string;
|
|
18
|
-
[key: string]: string | undefined;
|
|
19
|
-
};
|
|
20
|
-
plugins?: PluginConfig[];
|
|
21
|
-
template?: TemplateConfig;
|
|
22
|
-
frameworkOptions?: FrameworkOptions;
|
|
23
|
-
errorHandling?: {
|
|
24
|
-
skipOnError: boolean;
|
|
25
|
-
logLevel: 'debug' | 'info' | 'warn' | 'error';
|
|
26
|
-
maxRetries: number;
|
|
27
|
-
};
|
|
28
|
-
performance?: {
|
|
29
|
-
batchSize: number;
|
|
30
|
-
parallel: boolean;
|
|
31
|
-
timeout: number;
|
|
32
|
-
enableCache: boolean;
|
|
77
|
+
[property: string]: string;
|
|
33
78
|
};
|
|
79
|
+
responsive?: ResponsiveConfig;
|
|
80
|
+
theme?: ThemeConfig;
|
|
81
|
+
animations?: string[];
|
|
82
|
+
plugins: PluginConfig[];
|
|
83
|
+
exclude: string[];
|
|
84
|
+
include?: string[];
|
|
85
|
+
errorHandling: ErrorHandlingConfig;
|
|
86
|
+
performance: PerformanceConfig;
|
|
87
|
+
outputConfig: OutputConfig;
|
|
88
|
+
react?: ReactConfig;
|
|
89
|
+
vue?: VueConfig;
|
|
90
|
+
angular?: AngularConfig;
|
|
34
91
|
}
|
|
35
92
|
export interface FrameworkOptions {
|
|
36
93
|
composition?: boolean;
|
|
@@ -72,6 +129,7 @@ export interface ComponentGenerationOptions {
|
|
|
72
129
|
styleRules?: Record<string, string>;
|
|
73
130
|
template?: TemplateConfig;
|
|
74
131
|
frameworkOptions?: FrameworkOptions;
|
|
132
|
+
namingConvention?: 'kebab' | 'pascal' | 'camel';
|
|
75
133
|
}
|
|
76
134
|
export interface TemplateConfig {
|
|
77
135
|
type: 'default' | 'custom';
|
package/dist/utils/native.d.ts
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
1
|
+
type BufferEncoding = 'ascii' | 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2' | 'base64' | 'base64url' | 'latin1' | 'binary' | 'hex';
|
|
1
2
|
/**
|
|
2
3
|
* Native Node.js utilities to replace external dependencies
|
|
3
4
|
*/
|
|
4
5
|
/**
|
|
5
|
-
* Convert string to PascalCase
|
|
6
|
+
* Convert a string to PascalCase, preserving existing capital letters.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} str - Input string to convert.
|
|
9
|
+
* @returns {string} PascalCase string.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* toPascalCase('hello-world') => 'HelloWorld'
|
|
13
|
+
* toPascalCase('hello_world') => 'HelloWorld'
|
|
14
|
+
* toPascalCase('hello world') => 'HelloWorld'
|
|
15
|
+
* toPascalCase('ArrowBendDownLeft') => 'ArrowBendDownLeft'
|
|
6
16
|
*/
|
|
7
17
|
export declare function toPascalCase(str: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Convert a string to camelCase.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} str - Input string to convert.
|
|
22
|
+
* @returns {string} camelCase string.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* toCamelCase('hello-world') => 'helloWorld'
|
|
26
|
+
*/
|
|
27
|
+
export declare function toCamelCase(str: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Convert a string to kebab-case.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} str - Input string to convert.
|
|
32
|
+
* @returns {string} kebab-case string.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* toKebabCase('HelloWorld') => 'hello-world'
|
|
36
|
+
* toKebabCase('hello_world') => 'hello-world'
|
|
37
|
+
*/
|
|
38
|
+
export declare function toKebabCase(str: string): string;
|
|
8
39
|
/**
|
|
9
40
|
* Native file system utilities (replaces fs-extra package)
|
|
10
41
|
*/
|
package/dist/utils/native.js
CHANGED
|
@@ -4,15 +4,54 @@ import { promisify } from 'util';
|
|
|
4
4
|
* Native Node.js utilities to replace external dependencies
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
|
-
* Convert string to PascalCase
|
|
7
|
+
* Convert a string to PascalCase, preserving existing capital letters.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} str - Input string to convert.
|
|
10
|
+
* @returns {string} PascalCase string.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* toPascalCase('hello-world') => 'HelloWorld'
|
|
14
|
+
* toPascalCase('hello_world') => 'HelloWorld'
|
|
15
|
+
* toPascalCase('hello world') => 'HelloWorld'
|
|
16
|
+
* toPascalCase('ArrowBendDownLeft') => 'ArrowBendDownLeft'
|
|
8
17
|
*/
|
|
9
18
|
export function toPascalCase(str) {
|
|
19
|
+
// If the string is already in a good format (contains capital letters and no separators), preserve it
|
|
20
|
+
if (/^[A-Z][a-zA-Z0-9]*$/.test(str)) {
|
|
21
|
+
return str;
|
|
22
|
+
}
|
|
23
|
+
return str
|
|
24
|
+
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
|
|
25
|
+
.replace(/^(.)/, char => char.toUpperCase());
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convert a string to camelCase.
|
|
29
|
+
*
|
|
30
|
+
* @param {string} str - Input string to convert.
|
|
31
|
+
* @returns {string} camelCase string.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* toCamelCase('hello-world') => 'helloWorld'
|
|
35
|
+
*/
|
|
36
|
+
export function toCamelCase(str) {
|
|
37
|
+
const pascal = toPascalCase(str);
|
|
38
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Convert a string to kebab-case.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} str - Input string to convert.
|
|
44
|
+
* @returns {string} kebab-case string.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* toKebabCase('HelloWorld') => 'hello-world'
|
|
48
|
+
* toKebabCase('hello_world') => 'hello-world'
|
|
49
|
+
*/
|
|
50
|
+
export function toKebabCase(str) {
|
|
10
51
|
return str
|
|
11
|
-
.replace(/[
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
15
|
-
.join('');
|
|
52
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
53
|
+
.replace(/[\s_]+/g, '-')
|
|
54
|
+
.toLowerCase();
|
|
16
55
|
}
|
|
17
56
|
/**
|
|
18
57
|
* Native file system utilities (replaces fs-extra package)
|
|
@@ -154,7 +193,7 @@ export class CLI {
|
|
|
154
193
|
this.commands.set(command, {
|
|
155
194
|
description,
|
|
156
195
|
action: action,
|
|
157
|
-
options
|
|
196
|
+
options,
|
|
158
197
|
});
|
|
159
198
|
}
|
|
160
199
|
async parse() {
|
|
@@ -266,7 +305,7 @@ export class FileWatcher {
|
|
|
266
305
|
try {
|
|
267
306
|
const watcher = fs.watch(path, {
|
|
268
307
|
recursive: options?.recursive || false,
|
|
269
|
-
persistent: true
|
|
308
|
+
persistent: true,
|
|
270
309
|
}, (eventType, filename) => {
|
|
271
310
|
if (filename) {
|
|
272
311
|
this.emit(eventType, `${path}/${filename}`);
|
package/dist/watch.d.ts
CHANGED