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
package/src/cli.ts DELETED
@@ -1,221 +0,0 @@
1
- #!/usr/bin/env node
2
- import { CLI } from "./utils/native.js";
3
- import { svgService } from "./services/svg-service.js";
4
- import { configService } from "./services/config.js";
5
- import { logger } from "./core/logger.js";
6
-
7
- const program = new CLI();
8
-
9
- /**
10
- * svger-cli CLI
11
- * Custom SVG to Angular, React, Vue, Svelte, Solid, and other component converter.
12
- */
13
- program
14
- .name("svger-cli")
15
- .description("Custom SVG to Angular, React, Vue, Svelte, Solid, and other component converter")
16
- .version("2.0.0");
17
-
18
- // -------- Build Command --------
19
- /**
20
- * Build all SVGs from a source folder to an output folder.
21
- */
22
- program
23
- .command("build <src> <out>")
24
- .description("Build all SVGs from source to output")
25
- .option("--framework <type>", "Target framework (react|vue|svelte|angular|solid|preact|lit|vanilla)")
26
- .option("--typescript", "Generate TypeScript components (default: true)")
27
- .option("--no-typescript", "Generate JavaScript components")
28
- .option("--composition", "Use Vue Composition API with <script setup>")
29
- .option("--standalone", "Generate Angular standalone components")
30
- .option("--signals", "Use Angular signals for reactive state")
31
- .action(async (args: string[], opts: Record<string, any>) => {
32
- try {
33
- const [src, out] = args;
34
-
35
- // Build config from CLI options
36
- const buildConfig: any = { src, out };
37
-
38
- if (opts.framework) {
39
- buildConfig.framework = opts.framework;
40
- }
41
-
42
- if (opts.typescript !== undefined) {
43
- buildConfig.typescript = opts.typescript;
44
- }
45
-
46
- // Framework-specific options
47
- const frameworkOptions: any = {};
48
-
49
- if (opts.composition !== undefined) {
50
- frameworkOptions.scriptSetup = opts.composition;
51
- }
52
-
53
- if (opts.standalone !== undefined) {
54
- frameworkOptions.standalone = opts.standalone;
55
- }
56
-
57
- if (opts.signals !== undefined) {
58
- frameworkOptions.signals = opts.signals;
59
- }
60
-
61
- if (Object.keys(frameworkOptions).length > 0) {
62
- buildConfig.frameworkOptions = frameworkOptions;
63
- }
64
-
65
- await svgService.buildAll(buildConfig);
66
- } catch (error) {
67
- logger.error('Build failed:', error);
68
- process.exit(1);
69
- }
70
- });
71
-
72
- // -------- Watch Command --------
73
- /**
74
- * Watch a source folder and rebuild SVGs automatically on changes.
75
- */
76
- program
77
- .command("watch <src> <out>")
78
- .description("Watch source folder and rebuild SVGs automatically")
79
- .action(async (args: string[]) => {
80
- try {
81
- const [src, out] = args;
82
- await svgService.startWatching({ src, out });
83
-
84
- // Keep the process running
85
- process.on('SIGINT', () => {
86
- logger.info('Shutting down watch mode...');
87
- svgService.shutdown();
88
- process.exit(0);
89
- });
90
- } catch (error) {
91
- logger.error('Watch mode failed:', error);
92
- process.exit(1);
93
- }
94
- });
95
-
96
- // -------- Generate Single SVG --------
97
- /**
98
- * Generate a component from a single SVG file.
99
- */
100
- program
101
- .command("generate <svgFile> <out>")
102
- .description("Convert a single SVG file into a component")
103
- .option("--framework <type>", "Target framework (react|vue|svelte|angular|solid|preact|lit|vanilla)")
104
- .option("--typescript", "Generate TypeScript component (default: true)")
105
- .option("--no-typescript", "Generate JavaScript component")
106
- .option("--composition", "Use Vue Composition API with <script setup>")
107
- .option("--standalone", "Generate Angular standalone component")
108
- .action(async (args: string[], opts: Record<string, any>) => {
109
- try {
110
- const [svgFile, out] = args;
111
-
112
- const generateConfig: any = { svgFile, outDir: out };
113
-
114
- if (opts.framework) {
115
- generateConfig.framework = opts.framework;
116
- }
117
-
118
- if (opts.typescript !== undefined) {
119
- generateConfig.typescript = opts.typescript;
120
- }
121
-
122
- const frameworkOptions: any = {};
123
-
124
- if (opts.composition !== undefined) {
125
- frameworkOptions.scriptSetup = opts.composition;
126
- }
127
-
128
- if (opts.standalone !== undefined) {
129
- frameworkOptions.standalone = opts.standalone;
130
- }
131
-
132
- if (Object.keys(frameworkOptions).length > 0) {
133
- generateConfig.frameworkOptions = frameworkOptions;
134
- }
135
-
136
- await svgService.generateSingle(generateConfig);
137
- } catch (error) {
138
- logger.error('Generation failed:', error);
139
- process.exit(1);
140
- }
141
- });
142
-
143
- // -------- Lock / Unlock --------
144
- /**
145
- * Lock one or more SVG files to prevent accidental overwrites.
146
- */
147
- program
148
- .command("lock <files...>")
149
- .description("Lock one or more SVG files")
150
- .action((args: string[]) => {
151
- try {
152
- svgService.lockService.lockFiles(args);
153
- } catch (error) {
154
- logger.error('Lock operation failed:', error);
155
- process.exit(1);
156
- }
157
- });
158
-
159
- /**
160
- * Unlock one or more SVG files to allow modifications.
161
- */
162
- program
163
- .command("unlock <files...>")
164
- .description("Unlock one or more SVG files")
165
- .action((args: string[]) => {
166
- try {
167
- svgService.lockService.unlockFiles(args);
168
- } catch (error) {
169
- logger.error('Unlock operation failed:', error);
170
- process.exit(1);
171
- }
172
- });
173
-
174
- // -------- Config --------
175
- /**
176
- * Manage svger-cli configuration.
177
- */
178
- program
179
- .command("config")
180
- .description("Manage svger-cli configuration")
181
- .option("--init", "Create default .svgconfig.json")
182
- .option("--set <keyValue>", "Set config key=value")
183
- .option("--show", "Show current config")
184
- .action(async (args: string[], opts: Record<string, any>) => {
185
- try {
186
- if (opts.init) return await configService.initConfig();
187
- if (opts.set) {
188
- const [key, value] = opts.set.split("=");
189
- if (!key || value === undefined) {
190
- logger.error("Invalid format. Use key=value");
191
- process.exit(1);
192
- }
193
- const parsedValue = !isNaN(Number(value)) ? Number(value) : value;
194
- return configService.setConfig(key, parsedValue);
195
- }
196
- if (opts.show) return configService.showConfig();
197
- logger.error("No option provided. Use --init, --set, or --show");
198
- } catch (error) {
199
- logger.error('Config operation failed:', error);
200
- process.exit(1);
201
- }
202
- });
203
-
204
- // -------- Clean Command --------
205
- /**
206
- * Remove all generated SVG React components from an output folder.
207
- */
208
- program
209
- .command("clean <out>")
210
- .description("Remove all generated SVG React components from output folder")
211
- .action(async (args: string[]) => {
212
- try {
213
- const [out] = args;
214
- await svgService.clean(out);
215
- } catch (error) {
216
- logger.error('Clean operation failed:', error);
217
- process.exit(1);
218
- }
219
- });
220
-
221
- program.parse();
package/src/config.ts DELETED
@@ -1,81 +0,0 @@
1
- import path from "path";
2
- import { FileSystem } from "./utils/native.js";
3
-
4
- const CONFIG_FILE = ".svgconfig.json";
5
-
6
- /**
7
- * Get the absolute path to the configuration file.
8
- *
9
- * @returns {string} Absolute path to .svgconfig.json
10
- */
11
- function getConfigPath(): string {
12
- return path.resolve(CONFIG_FILE);
13
- }
14
-
15
- /**
16
- * Read the current svger-cli configuration.
17
- *
18
- * @returns {Record<string, any>} Configuration object. Returns an empty object if no config file exists.
19
- */
20
- export function readConfig(): Record<string, any> {
21
- return FileSystem.readJSONSync(getConfigPath());
22
- }
23
-
24
- /**
25
- * Write a configuration object to the config file.
26
- *
27
- * @param {Record<string, any>} config - Configuration object to write.
28
- */
29
- export function writeConfig(config: Record<string, any>) {
30
- FileSystem.writeJSONSync(getConfigPath(), config, { spaces: 2 });
31
- }
32
-
33
- /**
34
- * Initialize the svger-cli configuration with default values.
35
- * If a config file already exists, this function will not overwrite it.
36
- */
37
- export async function initConfig() {
38
- if (await FileSystem.exists(getConfigPath())) {
39
- console.log("⚠️ Config file already exists:", getConfigPath());
40
- return;
41
- }
42
-
43
- const defaultConfig = {
44
- source: "./src/assets/svg",
45
- output: "./src/components/icons",
46
- watch: false,
47
- defaultWidth: 24,
48
- defaultHeight: 24,
49
- defaultFill: "currentColor",
50
- exclude: [] as string[],
51
- styleRules: {
52
- fill: "inherit",
53
- stroke: "none",
54
- },
55
- };
56
-
57
- writeConfig(defaultConfig);
58
- console.log("✅ Config file created:", getConfigPath());
59
- }
60
-
61
- /**
62
- * Set a specific configuration key to a new value.
63
- *
64
- * @param {string} key - The config key to set.
65
- * @param {any} value - The value to assign to the key.
66
- */
67
- export function setConfig(key: string, value: any) {
68
- const config = readConfig();
69
- config[key] = value;
70
- writeConfig(config);
71
- console.log(`✅ Set config ${key}=${value}`);
72
- }
73
-
74
- /**
75
- * Display the current configuration in the console.
76
- */
77
- export function showConfig() {
78
- const config = readConfig();
79
- console.log("📄 Current Config:");
80
- console.log(JSON.stringify(config, null, 2));
81
- }
@@ -1,303 +0,0 @@
1
- import { logger } from '../core/logger.js';
2
-
3
- /**
4
- * Enhanced error handling system with detailed error tracking and recovery
5
- */
6
-
7
- export interface SVGError {
8
- code: string;
9
- message: string;
10
- severity: 'low' | 'medium' | 'high' | 'critical';
11
- context?: Record<string, any>;
12
- timestamp: number;
13
- stack?: string;
14
- }
15
-
16
- export interface ErrorRecoveryStrategy {
17
- canRecover(error: SVGError): boolean;
18
- recover(error: SVGError, context?: any): Promise<any>;
19
- }
20
-
21
- export class SVGErrorHandler {
22
- private static instance: SVGErrorHandler;
23
- private errorHistory: SVGError[] = [];
24
- private recoveryStrategies: Map<string, ErrorRecoveryStrategy> = new Map();
25
- private readonly maxHistorySize = 100;
26
-
27
- private constructor() {
28
- this.setupDefaultStrategies();
29
- }
30
-
31
- public static getInstance(): SVGErrorHandler {
32
- if (!SVGErrorHandler.instance) {
33
- SVGErrorHandler.instance = new SVGErrorHandler();
34
- }
35
- return SVGErrorHandler.instance;
36
- }
37
-
38
- /**
39
- * Handle an error with context and attempted recovery
40
- */
41
- public async handleError(
42
- error: Error | SVGError,
43
- context?: Record<string, any>
44
- ): Promise<{ recovered: boolean; result?: any }> {
45
- const svgError = this.normalizeError(error, context);
46
-
47
- // Log error based on severity
48
- this.logError(svgError);
49
-
50
- // Add to history
51
- this.addToHistory(svgError);
52
-
53
- // Attempt recovery
54
- const recoveryResult = await this.attemptRecovery(svgError, context);
55
-
56
- return recoveryResult;
57
- }
58
-
59
- /**
60
- * Register a custom error recovery strategy
61
- */
62
- public registerRecoveryStrategy(errorCode: string, strategy: ErrorRecoveryStrategy): void {
63
- this.recoveryStrategies.set(errorCode, strategy);
64
- logger.debug(`Recovery strategy registered for error code: ${errorCode}`);
65
- }
66
-
67
- /**
68
- * Get error statistics
69
- */
70
- public getErrorStats(): {
71
- total: number;
72
- bySeverity: Record<string, number>;
73
- byCode: Record<string, number>;
74
- recentErrors: SVGError[];
75
- } {
76
- const bySeverity: Record<string, number> = {};
77
- const byCode: Record<string, number> = {};
78
-
79
- this.errorHistory.forEach(error => {
80
- bySeverity[error.severity] = (bySeverity[error.severity] || 0) + 1;
81
- byCode[error.code] = (byCode[error.code] || 0) + 1;
82
- });
83
-
84
- return {
85
- total: this.errorHistory.length,
86
- bySeverity,
87
- byCode,
88
- recentErrors: this.errorHistory.slice(-10)
89
- };
90
- }
91
-
92
- /**
93
- * Clear error history
94
- */
95
- public clearHistory(): void {
96
- this.errorHistory = [];
97
- logger.debug('Error history cleared');
98
- }
99
-
100
- // Private methods
101
-
102
- private normalizeError(error: Error | SVGError, context?: Record<string, any>): SVGError {
103
- if ('code' in error && 'severity' in error) {
104
- return error as SVGError;
105
- }
106
-
107
- // Convert regular Error to SVGError
108
- const regularError = error as Error;
109
- return {
110
- code: this.categorizeError(regularError),
111
- message: regularError.message,
112
- severity: this.determineSeverity(regularError),
113
- context: context || {},
114
- timestamp: Date.now(),
115
- stack: regularError.stack
116
- };
117
- }
118
-
119
- private categorizeError(error: Error): string {
120
- const message = error.message.toLowerCase();
121
-
122
- if (message.includes('file not found') || message.includes('enoent')) {
123
- return 'FILE_NOT_FOUND';
124
- }
125
- if (message.includes('permission') || message.includes('eacces')) {
126
- return 'PERMISSION_DENIED';
127
- }
128
- if (message.includes('parse') || message.includes('syntax')) {
129
- return 'PARSE_ERROR';
130
- }
131
- if (message.includes('timeout')) {
132
- return 'TIMEOUT_ERROR';
133
- }
134
- if (message.includes('network') || message.includes('connection')) {
135
- return 'NETWORK_ERROR';
136
- }
137
- if (message.includes('svg') && message.includes('invalid')) {
138
- return 'INVALID_SVG';
139
- }
140
-
141
- return 'UNKNOWN_ERROR';
142
- }
143
-
144
- private determineSeverity(error: Error): SVGError['severity'] {
145
- const message = error.message.toLowerCase();
146
-
147
- if (message.includes('critical') || message.includes('fatal')) {
148
- return 'critical';
149
- }
150
- if (message.includes('file not found') || message.includes('permission')) {
151
- return 'high';
152
- }
153
- if (message.includes('parse') || message.includes('invalid')) {
154
- return 'medium';
155
- }
156
-
157
- return 'low';
158
- }
159
-
160
- private logError(error: SVGError): void {
161
- const logMessage = `[${error.code}] ${error.message}`;
162
-
163
- switch (error.severity) {
164
- case 'critical':
165
- logger.error('CRITICAL:', logMessage, error.context);
166
- break;
167
- case 'high':
168
- logger.error('HIGH:', logMessage, error.context);
169
- break;
170
- case 'medium':
171
- logger.warn('MEDIUM:', logMessage, error.context);
172
- break;
173
- case 'low':
174
- logger.info('LOW:', logMessage, error.context);
175
- break;
176
- }
177
- }
178
-
179
- private addToHistory(error: SVGError): void {
180
- this.errorHistory.push(error);
181
-
182
- // Maintain history size limit
183
- if (this.errorHistory.length > this.maxHistorySize) {
184
- this.errorHistory = this.errorHistory.slice(-this.maxHistorySize);
185
- }
186
- }
187
-
188
- private async attemptRecovery(
189
- error: SVGError,
190
- context?: any
191
- ): Promise<{ recovered: boolean; result?: any }> {
192
- const strategy = this.recoveryStrategies.get(error.code);
193
-
194
- if (!strategy) {
195
- logger.debug(`No recovery strategy found for error code: ${error.code}`);
196
- return { recovered: false };
197
- }
198
-
199
- try {
200
- if (!strategy.canRecover(error)) {
201
- logger.debug(`Recovery strategy declined to handle error: ${error.code}`);
202
- return { recovered: false };
203
- }
204
-
205
- logger.info(`Attempting recovery for error: ${error.code}`);
206
- const result = await strategy.recover(error, context);
207
-
208
- logger.success(`Successfully recovered from error: ${error.code}`);
209
- return { recovered: true, result };
210
-
211
- } catch (recoveryError) {
212
- logger.error(`Recovery failed for error ${error.code}:`, recoveryError);
213
- return { recovered: false };
214
- }
215
- }
216
-
217
- private setupDefaultStrategies(): void {
218
- // File not found recovery
219
- this.registerRecoveryStrategy('FILE_NOT_FOUND', {
220
- canRecover: (error) => error.context?.filePath && error.context?.canSkip === true,
221
- recover: async (error, context) => {
222
- logger.warn(`Skipping missing file: ${error.context?.filePath}`);
223
- return { skipped: true, filePath: error.context?.filePath };
224
- }
225
- });
226
-
227
- // Invalid SVG recovery
228
- this.registerRecoveryStrategy('INVALID_SVG', {
229
- canRecover: (error) => error.context?.svgContent,
230
- recover: async (error, context) => {
231
- logger.info('Attempting to clean invalid SVG content');
232
-
233
- // Basic SVG cleanup
234
- let cleaned = error.context?.svgContent || '';
235
-
236
- // Remove potentially problematic content
237
- cleaned = cleaned
238
- .replace(/<script[\s\S]*?<\/script>/gi, '') // Remove scripts
239
- .replace(/<style[\s\S]*?<\/style>/gi, '') // Remove styles
240
- .replace(/on\w+="[^"]*"/gi, '') // Remove event handlers
241
- .replace(/javascript:[^"']*/gi, ''); // Remove javascript: URLs
242
-
243
- return { cleanedContent: cleaned };
244
- }
245
- });
246
-
247
- // Permission denied recovery
248
- this.registerRecoveryStrategy('PERMISSION_DENIED', {
249
- canRecover: (error) => error.context?.alternative,
250
- recover: async (error, context) => {
251
- logger.warn(`Using alternative path due to permission issue: ${error.context?.alternative}`);
252
- return { alternativePath: error.context?.alternative };
253
- }
254
- });
255
-
256
- logger.debug('Default error recovery strategies loaded');
257
- }
258
- }
259
-
260
- // Export singleton instance and utilities
261
- export const errorHandler = SVGErrorHandler.getInstance();
262
-
263
- /**
264
- * Utility function to wrap async operations with error handling
265
- */
266
- export async function withErrorHandling<T>(
267
- operation: () => Promise<T>,
268
- context?: Record<string, any>
269
- ): Promise<T | null> {
270
- try {
271
- return await operation();
272
- } catch (error) {
273
- const result = await errorHandler.handleError(error as Error, context);
274
-
275
- if (result.recovered) {
276
- return result.result as T;
277
- }
278
-
279
- // Re-throw if not recovered and severity is high
280
- const svgError = error as any;
281
- if (svgError.severity === 'high' || svgError.severity === 'critical') {
282
- throw error;
283
- }
284
-
285
- return null;
286
- }
287
- }
288
-
289
- /**
290
- * Decorator for automatic error handling
291
- */
292
- export function handleErrors(context?: Record<string, any>) {
293
- return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
294
- const method = descriptor.value;
295
-
296
- descriptor.value = async function (...args: any[]) {
297
- return withErrorHandling(
298
- () => method.apply(this, args),
299
- { method: propertyName, ...context }
300
- );
301
- };
302
- };
303
- }
@@ -1,104 +0,0 @@
1
- import { Logger, LogLevel } from '../types/index.js';
2
-
3
- /**
4
- * Professional logging service with configurable levels and formatted output
5
- */
6
- export class LoggerService implements Logger {
7
- private static instance: LoggerService;
8
- private logLevel: LogLevel = 'info';
9
- private enableColors: boolean = true;
10
-
11
- private constructor() {}
12
-
13
- public static getInstance(): LoggerService {
14
- if (!LoggerService.instance) {
15
- LoggerService.instance = new LoggerService();
16
- }
17
- return LoggerService.instance;
18
- }
19
-
20
- public setLogLevel(level: LogLevel): void {
21
- this.logLevel = level;
22
- }
23
-
24
- public setColors(enabled: boolean): void {
25
- this.enableColors = enabled;
26
- }
27
-
28
- private shouldLog(level: LogLevel): boolean {
29
- const levels: LogLevel[] = ['debug', 'info', 'warn', 'error'];
30
- const currentIndex = levels.indexOf(this.logLevel);
31
- const messageIndex = levels.indexOf(level);
32
- return messageIndex >= currentIndex;
33
- }
34
-
35
- private formatMessage(level: LogLevel, message: string): string {
36
- const timestamp = new Date().toISOString();
37
- const prefix = this.getPrefix(level);
38
- return `${timestamp} ${prefix} ${message}`;
39
- }
40
-
41
- private getPrefix(level: LogLevel): string {
42
- if (!this.enableColors) {
43
- return `[${level.toUpperCase()}]`;
44
- }
45
-
46
- const colors = {
47
- debug: '\x1b[36m', // Cyan
48
- info: '\x1b[34m', // Blue
49
- warn: '\x1b[33m', // Yellow
50
- error: '\x1b[31m', // Red
51
- success: '\x1b[32m', // Green
52
- };
53
-
54
- const reset = '\x1b[0m';
55
- const color = colors[level as keyof typeof colors] || colors.info;
56
-
57
- const icons = {
58
- debug: '🔍',
59
- info: 'ℹ️',
60
- warn: '⚠️',
61
- error: '❌',
62
- success: '✅',
63
- };
64
-
65
- const icon = icons[level as keyof typeof icons] || icons.info;
66
- return `${color}${icon} [${level.toUpperCase()}]${reset}`;
67
- }
68
-
69
- public debug(message: string, ...args: any[]): void {
70
- if (this.shouldLog('debug')) {
71
- console.debug(this.formatMessage('debug', message), ...args);
72
- }
73
- }
74
-
75
- public info(message: string, ...args: any[]): void {
76
- if (this.shouldLog('info')) {
77
- console.info(this.formatMessage('info', message), ...args);
78
- }
79
- }
80
-
81
- public warn(message: string, ...args: any[]): void {
82
- if (this.shouldLog('warn')) {
83
- console.warn(this.formatMessage('warn', message), ...args);
84
- }
85
- }
86
-
87
- public error(message: string, ...args: any[]): void {
88
- if (this.shouldLog('error')) {
89
- console.error(this.formatMessage('error', message), ...args);
90
- }
91
- }
92
-
93
- public success(message: string, ...args: any[]): void {
94
- if (this.shouldLog('info')) {
95
- const timestamp = new Date().toISOString();
96
- const prefix = this.getPrefix('info');
97
- const successPrefix = this.enableColors ? '✅ [SUCCESS]' : '[SUCCESS]';
98
- console.log(`${timestamp} ${successPrefix} ${message}`, ...args);
99
- }
100
- }
101
- }
102
-
103
- // Export singleton instance
104
- export const logger = LoggerService.getInstance();