svger-cli 2.0.1 → 2.0.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.
Files changed (91) hide show
  1. package/.svgerconfig.example.json +38 -0
  2. package/CHANGELOG.md +64 -0
  3. package/DEVELOPMENT.md +353 -0
  4. package/README.md +24 -5
  5. package/SECURITY.md +69 -0
  6. package/dist/builder.js +16 -16
  7. package/dist/clean.js +2 -2
  8. package/dist/cli.js +38 -38
  9. package/dist/config.js +11 -11
  10. package/dist/core/error-handler.d.ts +63 -0
  11. package/dist/core/error-handler.js +227 -0
  12. package/dist/core/framework-templates.d.ts +17 -0
  13. package/{src/core/framework-templates.ts → dist/core/framework-templates.js} +104 -139
  14. package/dist/core/logger.d.ts +22 -0
  15. package/dist/core/logger.js +85 -0
  16. package/dist/core/performance-engine.d.ts +67 -0
  17. package/dist/core/performance-engine.js +252 -0
  18. package/dist/core/plugin-manager.d.ts +56 -0
  19. package/dist/core/plugin-manager.js +191 -0
  20. package/dist/core/style-compiler.d.ts +88 -0
  21. package/dist/core/style-compiler.js +468 -0
  22. package/dist/core/template-manager.d.ts +64 -0
  23. package/{src/core/template-manager.ts → dist/core/template-manager.js} +172 -255
  24. package/dist/index.d.ts +153 -0
  25. package/{src/index.ts → dist/index.js} +32 -110
  26. package/dist/lock.js +7 -7
  27. package/dist/processors/svg-processor.d.ts +73 -0
  28. package/dist/processors/svg-processor.js +261 -0
  29. package/dist/services/config.d.ts +55 -0
  30. package/dist/services/config.js +211 -0
  31. package/dist/services/file-watcher.d.ts +54 -0
  32. package/dist/services/file-watcher.js +180 -0
  33. package/dist/services/svg-service.d.ts +81 -0
  34. package/dist/services/svg-service.js +395 -0
  35. package/dist/templates/ComponentTemplate.js +25 -25
  36. package/dist/types/index.d.ts +146 -0
  37. package/dist/types/index.js +4 -0
  38. package/dist/utils/native.d.ts +104 -0
  39. package/dist/utils/native.js +340 -0
  40. package/dist/watch.d.ts +1 -1
  41. package/dist/watch.js +14 -14
  42. package/package.json +154 -14
  43. package/.svgconfig.json +0 -3
  44. package/CODE_OF_CONDUCT.md +0 -79
  45. package/CONTRIBUTING.md +0 -146
  46. package/TESTING.md +0 -143
  47. package/cli-framework.test.js +0 -16
  48. package/cli-test-angular/Arrowbenddownleft.component.ts +0 -27
  49. package/cli-test-angular/Vite.component.ts +0 -27
  50. package/cli-test-angular/index.ts +0 -25
  51. package/cli-test-output/Arrowbenddownleft.vue +0 -33
  52. package/cli-test-output/Vite.vue +0 -33
  53. package/cli-test-output/index.ts +0 -25
  54. package/cli-test-react/Arrowbenddownleft.tsx +0 -39
  55. package/cli-test-react/Vite.tsx +0 -39
  56. package/cli-test-react/index.ts +0 -25
  57. package/cli-test-svelte/Arrowbenddownleft.svelte +0 -22
  58. package/cli-test-svelte/Vite.svelte +0 -22
  59. package/cli-test-svelte/index.ts +0 -25
  60. package/frameworks.test.js +0 -170
  61. package/my-svgs/ArrowBendDownLeft.svg +0 -6
  62. package/my-svgs/vite.svg +0 -1
  63. package/src/builder.ts +0 -104
  64. package/src/clean.ts +0 -21
  65. package/src/cli.ts +0 -221
  66. package/src/config.ts +0 -81
  67. package/src/core/error-handler.ts +0 -303
  68. package/src/core/logger.ts +0 -104
  69. package/src/core/performance-engine.ts +0 -327
  70. package/src/core/plugin-manager.ts +0 -228
  71. package/src/core/style-compiler.ts +0 -605
  72. package/src/lock.ts +0 -74
  73. package/src/processors/svg-processor.ts +0 -288
  74. package/src/services/config.ts +0 -241
  75. package/src/services/file-watcher.ts +0 -218
  76. package/src/services/svg-service.ts +0 -468
  77. package/src/templates/ComponentTemplate.ts +0 -57
  78. package/src/types/index.ts +0 -169
  79. package/src/utils/native.ts +0 -352
  80. package/src/watch.ts +0 -88
  81. package/test-output-mulit/TestIcon-angular-module.component.ts +0 -26
  82. package/test-output-mulit/TestIcon-angular-standalone.component.ts +0 -27
  83. package/test-output-mulit/TestIcon-lit.ts +0 -35
  84. package/test-output-mulit/TestIcon-preact.tsx +0 -38
  85. package/test-output-mulit/TestIcon-react.tsx +0 -35
  86. package/test-output-mulit/TestIcon-solid.tsx +0 -27
  87. package/test-output-mulit/TestIcon-svelte.svelte +0 -22
  88. package/test-output-mulit/TestIcon-vanilla.ts +0 -37
  89. package/test-output-mulit/TestIcon-vue-composition.vue +0 -33
  90. package/test-output-mulit/TestIcon-vue-options.vue +0 -31
  91. package/tsconfig.json +0 -18
@@ -1,57 +0,0 @@
1
- /**
2
- * Generates a React SVG component template from provided SVG content.
3
- *
4
- * This function processes raw SVG content by cleaning it (removing XML declarations,
5
- * DOCTYPE, extra whitespace, inline styles, and xmlns attributes), then wraps it in
6
- * a React functional component that accepts standard SVGProps for flexibility.
7
- *
8
- * @param options - Configuration object for generating the component.
9
- * @param options.componentName - The name of the React component (e.g., "IconName").
10
- * @param options.svgContent - The raw SVG markup as a string.
11
- * @param [options.defaultWidth=24] - The default width attribute for the SVG.
12
- * @param [options.defaultHeight=24] - The default height attribute for the SVG.
13
- * @param [options.defaultFill="currentColor"] - The default fill color for the SVG.
14
- * @returns A string containing the complete TypeScript code for the React SVG component.
15
- */
16
- export function reactTemplate({
17
- componentName,
18
- svgContent,
19
- defaultWidth = 24,
20
- defaultHeight = 24,
21
- defaultFill = "currentColor",
22
- }: {
23
- componentName: string;
24
- svgContent: string;
25
- defaultWidth?: number;
26
- defaultHeight?: number;
27
- defaultFill?: string;
28
- }) {
29
- const cleaned = svgContent
30
- .replace(/<\?xml.*?\?>/g, "")
31
- .replace(/<!DOCTYPE.*?>/g, "")
32
- .replace(/\r?\n|\r/g, "")
33
- .replace(/\s{2,}/g, " ")
34
- .replace(/style="[^"]*"/g, "")
35
- .replace(/\s+xmlns(:xlink)?="[^"]*"/g, "")
36
- .trim()
37
- .replace(/^.*?<svg[^>]*>(.*?)<\/svg>.*$/i, "$1");
38
-
39
- return `import type { SVGProps } from "react";
40
- const Svg${componentName} = (props: SVGProps<SVGSVGElement>) => (
41
- <svg
42
- viewBox="0 0 ${defaultWidth} ${defaultHeight}"
43
- xmlns="http://www.w3.org/2000/svg"
44
- xmlnsXlink="http://www.w3.org/1999/xlink"
45
- width={props.width || ${defaultWidth}}
46
- height={props.height || ${defaultHeight}}
47
- fill={props.fill || "${defaultFill}"}
48
- stroke={props.stroke || "none"}
49
- className={props.className}
50
- {...props}
51
- >
52
- ${cleaned}
53
- </svg>
54
- );
55
- export default Svg${componentName};
56
- `;
57
- }
@@ -1,169 +0,0 @@
1
- /**
2
- * Type definitions for svger-cli
3
- */
4
-
5
- export type FrameworkType = 'react' | 'vue' | 'svelte' | 'angular' | 'solid' | 'preact' | 'lit' | 'vanilla';
6
-
7
- export interface SVGConfig {
8
- source: string;
9
- output: string;
10
- watch: boolean;
11
- framework: FrameworkType;
12
- typescript: boolean;
13
- defaultWidth: number;
14
- defaultHeight: number;
15
- defaultFill: string;
16
- exclude: string[];
17
- styleRules: {
18
- fill?: string;
19
- stroke?: string;
20
- [key: string]: string | undefined;
21
- };
22
- plugins?: PluginConfig[];
23
- template?: TemplateConfig;
24
- frameworkOptions?: FrameworkOptions;
25
- errorHandling?: {
26
- skipOnError: boolean;
27
- logLevel: 'debug' | 'info' | 'warn' | 'error';
28
- maxRetries: number;
29
- };
30
- performance?: {
31
- batchSize: number;
32
- parallel: boolean;
33
- timeout: number;
34
- enableCache: boolean;
35
- };
36
- }
37
-
38
- export interface FrameworkOptions {
39
- // Vue-specific
40
- composition?: boolean;
41
- setup?: boolean;
42
- scriptSetup?: boolean;
43
-
44
- // Angular-specific
45
- standalone?: boolean;
46
- moduleImport?: boolean;
47
-
48
- // Solid-specific
49
- signals?: boolean;
50
-
51
- // React/Preact-specific
52
- forwardRef?: boolean;
53
- memo?: boolean;
54
-
55
- // Lit-specific
56
- customElement?: boolean;
57
- shadowDom?: boolean;
58
-
59
- // General
60
- cssModules?: boolean;
61
- styledComponents?: boolean;
62
- }
63
-
64
- export interface BuildOptions {
65
- src: string;
66
- out: string;
67
- config?: Partial<SVGConfig>;
68
- }
69
-
70
- export interface GenerateOptions {
71
- svgFile: string;
72
- outDir: string;
73
- config?: Partial<SVGConfig>;
74
- }
75
-
76
- export interface WatchOptions {
77
- src: string;
78
- out: string;
79
- config?: Partial<SVGConfig>;
80
- }
81
-
82
- export interface ComponentGenerationOptions {
83
- componentName: string;
84
- svgContent: string;
85
- framework: FrameworkType;
86
- typescript: boolean;
87
- defaultWidth?: number;
88
- defaultHeight?: number;
89
- defaultFill?: string;
90
- styleRules?: Record<string, string>;
91
- template?: TemplateConfig;
92
- frameworkOptions?: FrameworkOptions;
93
- }
94
-
95
- export interface TemplateConfig {
96
- type: 'default' | 'custom';
97
- path?: string;
98
- options?: Record<string, any>;
99
- }
100
-
101
- export interface PluginConfig {
102
- name: string;
103
- options?: Record<string, any>;
104
- }
105
-
106
- export interface SVGProcessorResult {
107
- success: boolean;
108
- componentName: string;
109
- filePath: string;
110
- error?: Error;
111
- }
112
-
113
- export interface FileWatchEvent {
114
- type: 'add' | 'change' | 'unlink';
115
- filePath: string;
116
- timestamp: number;
117
- }
118
-
119
- export interface ProcessingContext {
120
- config: SVGConfig;
121
- sourceDir: string;
122
- outputDir: string;
123
- fileQueue: string[];
124
- locks: Set<string>;
125
- cache?: Map<string, CachedComponent>;
126
- }
127
-
128
- export interface CachedComponent {
129
- hash: string;
130
- componentName: string;
131
- filePath: string;
132
- framework: FrameworkType;
133
- timestamp: number;
134
- svgHash: string;
135
- }
136
-
137
- export interface Logger {
138
- info(message: string, ...args: any[]): void;
139
- warn(message: string, ...args: any[]): void;
140
- error(message: string, ...args: any[]): void;
141
- success(message: string, ...args: any[]): void;
142
- debug(message: string, ...args: any[]): void;
143
- }
144
-
145
- export interface Plugin {
146
- name: string;
147
- version: string;
148
- process(content: string, options?: any): Promise<string>;
149
- validate?(options?: any): boolean;
150
- }
151
-
152
- export interface Template {
153
- name: string;
154
- generate(options: ComponentGenerationOptions): string;
155
- validate?(options: ComponentGenerationOptions): boolean;
156
- }
157
-
158
- export type FileSystemEvent = 'change' | 'rename';
159
- export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
160
- export type ProcessingStatus = 'pending' | 'processing' | 'completed' | 'failed';
161
-
162
- export interface ProcessingJob {
163
- id: string;
164
- filePath: string;
165
- status: ProcessingStatus;
166
- startTime: number;
167
- endTime?: number;
168
- error?: Error;
169
- }
@@ -1,352 +0,0 @@
1
- import fs from 'fs';
2
- import { promisify } from 'util';
3
-
4
- /**
5
- * Native Node.js utilities to replace external dependencies
6
- */
7
-
8
- /**
9
- * Convert string to PascalCase (replaces change-case package)
10
- */
11
- export function toPascalCase(str: string): string {
12
- return str
13
- .replace(/[^a-zA-Z0-9]/g, ' ')
14
- .split(' ')
15
- .filter(Boolean)
16
- .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
17
- .join('');
18
- }
19
-
20
- /**
21
- * Native file system utilities (replaces fs-extra package)
22
- */
23
- export class FileSystem {
24
- private static _readFile = promisify(fs.readFile);
25
- private static _writeFile = promisify(fs.writeFile);
26
- private static _readdir = promisify(fs.readdir);
27
- private static _stat = promisify(fs.stat);
28
- private static _mkdir = promisify(fs.mkdir);
29
- private static _rmdir = promisify(fs.rmdir);
30
- private static _unlink = promisify(fs.unlink);
31
-
32
- static async exists(path: string): Promise<boolean> {
33
- try {
34
- await this._stat(path);
35
- return true;
36
- } catch {
37
- return false;
38
- }
39
- }
40
-
41
- static async readFile(path: string, encoding: BufferEncoding = 'utf8'): Promise<string> {
42
- return this._readFile(path, encoding);
43
- }
44
-
45
- static async writeFile(path: string, content: string, encoding: BufferEncoding = 'utf8'): Promise<void> {
46
- return this._writeFile(path, content, encoding);
47
- }
48
-
49
- static async readDir(path: string): Promise<string[]> {
50
- return this._readdir(path);
51
- }
52
-
53
- static async ensureDir(dirPath: string): Promise<void> {
54
- try {
55
- await this._mkdir(dirPath, { recursive: true });
56
- } catch (error: any) {
57
- if (error.code !== 'EEXIST') {
58
- throw error;
59
- }
60
- }
61
- }
62
-
63
- static async removeDir(dirPath: string): Promise<void> {
64
- try {
65
- const files = await this._readdir(dirPath);
66
-
67
- for (const file of files) {
68
- const filePath = `${dirPath}/${file}`;
69
- const stats = await this._stat(filePath);
70
-
71
- if (stats.isDirectory()) {
72
- await this.removeDir(filePath);
73
- } else {
74
- await this._unlink(filePath);
75
- }
76
- }
77
-
78
- await this._rmdir(dirPath);
79
- } catch (error: any) {
80
- if (error.code !== 'ENOENT') {
81
- throw error;
82
- }
83
- }
84
- }
85
-
86
- static async emptyDir(dirPath: string): Promise<void> {
87
- if (!(await this.exists(dirPath))) {
88
- return;
89
- }
90
-
91
- const files = await this._readdir(dirPath);
92
-
93
- for (const file of files) {
94
- const filePath = `${dirPath}/${file}`;
95
- const stats = await this._stat(filePath);
96
-
97
- if (stats.isDirectory()) {
98
- await this.removeDir(filePath);
99
- } else {
100
- await this._unlink(filePath);
101
- }
102
- }
103
- }
104
-
105
- static async unlink(filePath: string): Promise<void> {
106
- return this._unlink(filePath);
107
- }
108
-
109
- static readJSONSync(path: string): any {
110
- try {
111
- const content = fs.readFileSync(path, 'utf8');
112
- return JSON.parse(content);
113
- } catch {
114
- return {};
115
- }
116
- }
117
-
118
- static writeJSONSync(path: string, data: any, options?: { spaces?: number }): void {
119
- const content = JSON.stringify(data, null, options?.spaces || 0);
120
- fs.writeFileSync(path, content, 'utf8');
121
- }
122
-
123
- static existsSync(path: string): boolean {
124
- try {
125
- fs.statSync(path);
126
- return true;
127
- } catch {
128
- return false;
129
- }
130
- }
131
-
132
- static ensureDirSync(dirPath: string): void {
133
- try {
134
- fs.mkdirSync(dirPath, { recursive: true });
135
- } catch (error: any) {
136
- if (error.code !== 'EEXIST') {
137
- throw error;
138
- }
139
- }
140
- }
141
- }
142
-
143
- /**
144
- * Simple CLI argument parser (replaces commander package)
145
- */
146
- export class CLI {
147
- private commands: Map<string, {
148
- description: string;
149
- action: (args: string[], options: Record<string, any>) => void | Promise<void>;
150
- options: Map<string, { description: string; hasValue: boolean }>;
151
- }> = new Map();
152
-
153
- private programName = '';
154
- private programDescription = '';
155
- private programVersion = '';
156
-
157
- name(name: string): this {
158
- this.programName = name;
159
- return this;
160
- }
161
-
162
- description(desc: string): this {
163
- this.programDescription = desc;
164
- return this;
165
- }
166
-
167
- version(version: string): this {
168
- this.programVersion = version;
169
- return this;
170
- }
171
-
172
- command(signature: string): CommandBuilder {
173
- return new CommandBuilder(signature, this);
174
- }
175
-
176
- addCommand(signature: string, description: string, action: Function, options: Map<string, any>): void {
177
- const [command] = signature.split(' ');
178
- this.commands.set(command, {
179
- description,
180
- action: action as any,
181
- options
182
- });
183
- }
184
-
185
- async parse(): Promise<void> {
186
- const args = process.argv.slice(2);
187
-
188
- if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
189
- this.showHelp();
190
- return;
191
- }
192
-
193
- if (args[0] === '--version' || args[0] === '-v') {
194
- console.log(this.programVersion);
195
- return;
196
- }
197
-
198
- const [commandName, ...remainingArgs] = args;
199
- const command = this.commands.get(commandName);
200
-
201
- if (!command) {
202
- console.error(`Unknown command: ${commandName}`);
203
- this.showHelp();
204
- process.exit(1);
205
- }
206
-
207
- const { parsedArgs, options } = this.parseArgs(remainingArgs, command.options);
208
-
209
- try {
210
- await command.action(parsedArgs, options);
211
- } catch (error) {
212
- console.error('Command failed:', error);
213
- process.exit(1);
214
- }
215
- }
216
-
217
- private parseArgs(args: string[], commandOptions: Map<string, any>): {
218
- parsedArgs: string[];
219
- options: Record<string, any>;
220
- } {
221
- const parsedArgs: string[] = [];
222
- const options: Record<string, any> = {};
223
-
224
- let i = 0;
225
- while (i < args.length) {
226
- const arg = args[i];
227
-
228
- if (arg.startsWith('--')) {
229
- const optionName = arg.slice(2);
230
- const optionConfig = commandOptions.get(optionName);
231
-
232
- if (optionConfig) {
233
- if (optionConfig.hasValue) {
234
- options[optionName] = args[i + 1];
235
- i += 2;
236
- } else {
237
- options[optionName] = true;
238
- i++;
239
- }
240
- } else {
241
- // Handle key=value format
242
- if (arg.includes('=')) {
243
- const [key, value] = arg.slice(2).split('=');
244
- options[key] = value;
245
- i++;
246
- } else {
247
- i++;
248
- }
249
- }
250
- } else {
251
- parsedArgs.push(arg);
252
- i++;
253
- }
254
- }
255
-
256
- return { parsedArgs, options };
257
- }
258
-
259
- private showHelp(): void {
260
- console.log(`${this.programName} - ${this.programDescription}`);
261
- console.log(`Version: ${this.programVersion}\n`);
262
- console.log('Commands:');
263
-
264
- for (const [name, cmd] of this.commands) {
265
- console.log(` ${name.padEnd(15)} ${cmd.description}`);
266
- }
267
-
268
- console.log('\nOptions:');
269
- console.log(' --help, -h Show help');
270
- console.log(' --version, -v Show version');
271
- }
272
- }
273
-
274
- class CommandBuilder {
275
- private signature: string;
276
- private desc = '';
277
- private cli: CLI;
278
- private options: Map<string, { description: string; hasValue: boolean }> = new Map();
279
-
280
- constructor(signature: string, cli: CLI) {
281
- this.signature = signature;
282
- this.cli = cli;
283
- }
284
-
285
- description(desc: string): this {
286
- this.desc = desc;
287
- return this;
288
- }
289
-
290
- option(flag: string, description: string): this {
291
- const hasValue = flag.includes('<') || flag.includes('[');
292
- const optionName = flag.split(' ')[0].replace(/^--/, '');
293
- this.options.set(optionName, { description, hasValue });
294
- return this;
295
- }
296
-
297
- action(fn: Function): void {
298
- this.cli.addCommand(this.signature, this.desc, fn, this.options);
299
- }
300
- }
301
-
302
- /**
303
- * File watcher using native fs.watch (replaces chokidar)
304
- */
305
- export class FileWatcher {
306
- private watchers: fs.FSWatcher[] = [];
307
- private callbacks: Map<string, Function[]> = new Map();
308
-
309
- watch(path: string, options?: { recursive?: boolean }): this {
310
- try {
311
- const watcher = fs.watch(path, {
312
- recursive: options?.recursive || false,
313
- persistent: true
314
- }, (eventType, filename) => {
315
- if (filename) {
316
- this.emit(eventType, `${path}/${filename}`);
317
- }
318
- });
319
-
320
- this.watchers.push(watcher);
321
- } catch (error) {
322
- console.error(`Failed to watch ${path}:`, error);
323
- }
324
-
325
- return this;
326
- }
327
-
328
- on(event: string, callback: Function): this {
329
- if (!this.callbacks.has(event)) {
330
- this.callbacks.set(event, []);
331
- }
332
- this.callbacks.get(event)!.push(callback);
333
- return this;
334
- }
335
-
336
- private emit(event: string, ...args: any[]): void {
337
- const callbacks = this.callbacks.get(event) || [];
338
- callbacks.forEach(callback => {
339
- try {
340
- callback(...args);
341
- } catch (error) {
342
- console.error('Watcher callback error:', error);
343
- }
344
- });
345
- }
346
-
347
- close(): void {
348
- this.watchers.forEach(watcher => watcher.close());
349
- this.watchers = [];
350
- this.callbacks.clear();
351
- }
352
- }
package/src/watch.ts DELETED
@@ -1,88 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { generateSVG } from "./builder.js";
4
- import { isLocked } from "./lock.js";
5
- import { readConfig } from "./config.js";
6
- import { FileSystem, FileWatcher } from "./utils/native.js";
7
-
8
- /**
9
- * Watches a source folder for changes to SVG files and automatically
10
- * rebuilds React components when SVGs are added, modified, or deleted.
11
- *
12
- * @param {Object} config - Watch configuration object.
13
- * @param {string} config.src - Source folder containing SVG files to watch.
14
- * @param {string} config.out - Output folder where React components are generated.
15
- * @returns {import("chokidar").FSWatcher} A chokidar file watcher instance.
16
- *
17
- * @example
18
- * watchSVGs({ src: "./src/assets/svg", out: "./src/components/icons" });
19
- *
20
- * // Watches the SVG folder and:
21
- * // - Generates new components when files are added.
22
- * // - Updates components when files change.
23
- * // - Removes components when SVGs are deleted.
24
- */
25
- export async function watchSVGs(config: { src: string; out: string }) {
26
- const srcDir = path.resolve(config.src);
27
- const outDir = path.resolve(config.out);
28
- const svgConfig = readConfig();
29
-
30
- if (!(await FileSystem.exists(srcDir))) {
31
- console.error("❌ Source folder not found:", srcDir);
32
- process.exit(1);
33
- }
34
-
35
- console.log(`👀 Watching for SVG changes in: ${srcDir}`);
36
- console.log("🚀 Watch mode active — waiting for file changes...");
37
-
38
- const watcher = new FileWatcher();
39
-
40
- // Watch the directory
41
- watcher.watch(srcDir, { recursive: false });
42
-
43
- // Handle file changes
44
- watcher.on("change", async (filePath: string) => {
45
- if (!filePath.endsWith(".svg")) return;
46
-
47
- console.log("Detected change in file:", filePath);
48
-
49
- if (isLocked(filePath)) {
50
- console.log(`⚠️ Skipped locked file: ${path.basename(filePath)}`);
51
- return;
52
- }
53
-
54
- console.log(`✏️ SVG updated: ${path.basename(filePath)}`);
55
- await generateSVG({ svgFile: filePath, outDir });
56
- });
57
-
58
- // Handle new files (rename event in fs.watch can indicate new files)
59
- watcher.on("rename", async (filePath: string) => {
60
- if (!filePath.endsWith(".svg")) return;
61
-
62
- // Check if file exists (new file) or doesn't exist (deleted file)
63
- const exists = await FileSystem.exists(filePath);
64
-
65
- if (exists) {
66
- console.log("Detected new file:", filePath);
67
-
68
- if (isLocked(filePath)) {
69
- console.log(`⚠️ Skipped locked file: ${path.basename(filePath)}`);
70
- return;
71
- }
72
-
73
- console.log(`➕ New SVG detected: ${path.basename(filePath)}`);
74
- await generateSVG({ svgFile: filePath, outDir });
75
- } else {
76
- // File was deleted
77
- const componentName = path.basename(filePath, ".svg");
78
- const outFile = path.join(outDir, `${componentName}.tsx`);
79
-
80
- if (await FileSystem.exists(outFile)) {
81
- await FileSystem.unlink(outFile);
82
- console.log(`🗑️ Removed component: ${componentName}.tsx`);
83
- }
84
- }
85
- });
86
-
87
- return watcher;
88
- }
@@ -1,26 +0,0 @@
1
- import { Component, Input } from '@angular/core';
2
-
3
- @Component({
4
- selector: 'test-icon',
5
-
6
- template: `
7
- <svg
8
- [attr.class]="className"
9
- [attr.width]="width"
10
- [attr.height]="height"
11
- [attr.fill]="fill"
12
- [attr.stroke]="stroke"
13
- viewBox="0 0 24 24"
14
- xmlns="http://www.w3.org/2000/svg"
15
- >
16
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
17
- </svg>
18
- `,
19
- })
20
- export class TestIconComponent {
21
- @Input() className: string = '';
22
- @Input() width: string | number = 24;
23
- @Input() height: string | number = 24;
24
- @Input() fill: string = 'currentColor';
25
- @Input() stroke: string = '';
26
- }