svger-cli 2.0.7 → 3.0.0

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.
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Official Babel Plugin for SVGER-CLI
3
+ *
4
+ * Transforms SVG imports into framework components during Babel transpilation.
5
+ * Works with any Babel-based build process including standalone Babel, Create React App,
6
+ * and other tools that use Babel under the hood.
7
+ *
8
+ * @example
9
+ * ```js
10
+ * // babel.config.js
11
+ * const { svgerBabelPlugin } = require('svger-cli/babel');
12
+ *
13
+ * module.exports = {
14
+ * plugins: [
15
+ * [svgerBabelPlugin, {
16
+ * source: './src/icons',
17
+ * output: './src/components/icons',
18
+ * framework: 'react',
19
+ * typescript: true
20
+ * }]
21
+ * ]
22
+ * };
23
+ * ```
24
+ *
25
+ * @example
26
+ * ```js
27
+ * // Direct SVG import transformation
28
+ * import Icon from './icon.svg';
29
+ * // Transforms to:
30
+ * import Icon from './components/icons/Icon';
31
+ * ```
32
+ */
33
+ import path from 'path';
34
+ import { FileSystem } from '../utils/native.js';
35
+ import { svgProcessor } from '../processors/svg-processor.js';
36
+ import { configService } from '../services/config.js';
37
+ import { logger } from '../core/logger.js';
38
+ const PLUGIN_NAME = 'svger-babel-plugin';
39
+ /**
40
+ * Process all SVG files in the source directory
41
+ */
42
+ async function processAllSVGs(options, processedFiles) {
43
+ const sourcePath = path.resolve(options.source);
44
+ const outputPath = path.resolve(options.output);
45
+ if (!(await FileSystem.exists(sourcePath))) {
46
+ logger.warn(`Source directory not found: ${sourcePath}`);
47
+ return [];
48
+ }
49
+ const files = await FileSystem.readDir(sourcePath);
50
+ const svgFiles = files.filter(file => file.endsWith('.svg'));
51
+ const results = [];
52
+ for (const file of svgFiles) {
53
+ const filePath = path.join(sourcePath, file);
54
+ if (processedFiles.has(filePath))
55
+ continue;
56
+ try {
57
+ const svgContent = await FileSystem.readFile(filePath, 'utf-8');
58
+ const componentName = svgProcessor.generateComponentName(file, 'pascal');
59
+ const config = configService.readConfig();
60
+ const component = await svgProcessor.generateComponent(componentName, svgContent, {
61
+ framework: options.framework,
62
+ typescript: options.typescript,
63
+ defaultWidth: config.defaultWidth,
64
+ defaultHeight: config.defaultHeight,
65
+ defaultFill: config.defaultFill,
66
+ styleRules: config.styleRules || {},
67
+ });
68
+ const ext = options.typescript ? 'tsx' : 'jsx';
69
+ const outputFile = path.join(outputPath, `${componentName}.${ext}`);
70
+ await FileSystem.ensureDir(path.dirname(outputFile));
71
+ await FileSystem.writeFile(outputFile, component);
72
+ processedFiles.add(filePath);
73
+ results.push({
74
+ success: true,
75
+ outputPath: outputFile,
76
+ componentName,
77
+ });
78
+ }
79
+ catch (error) {
80
+ logger.error(`Failed to process ${file}:`, error);
81
+ results.push({
82
+ success: false,
83
+ error: error,
84
+ });
85
+ }
86
+ }
87
+ // Generate index file if enabled
88
+ if (options.generateIndex && results.length > 0) {
89
+ try {
90
+ await generateIndexFile(outputPath, results, options);
91
+ }
92
+ catch (error) {
93
+ logger.error('Failed to generate index file:', error);
94
+ }
95
+ }
96
+ return results;
97
+ }
98
+ /**
99
+ * Generate index file with all exports
100
+ */
101
+ async function generateIndexFile(outputDir, results, options) {
102
+ const extension = options.typescript ? 'ts' : 'js';
103
+ const exports = results
104
+ .filter(r => r.componentName)
105
+ .map(r => `export { default as ${r.componentName} } from './${r.componentName}';`)
106
+ .join('\n');
107
+ const indexPath = path.join(outputDir, `index.${extension}`);
108
+ await FileSystem.writeFile(indexPath, exports, 'utf-8');
109
+ logger.debug(`Generated index file: ${indexPath}`);
110
+ }
111
+ /**
112
+ * Transform SVG import path to component path
113
+ */
114
+ function transformSVGImport(sourcePath, options) {
115
+ if (!sourcePath.endsWith('.svg'))
116
+ return null;
117
+ const absoluteOutput = path.resolve(options.output);
118
+ // Extract filename without extension
119
+ const fileName = path.basename(sourcePath, '.svg');
120
+ const componentName = svgProcessor.generateComponentName(fileName, 'pascal');
121
+ // Calculate relative path from output to component
122
+ const ext = options.typescript ? 'tsx' : 'jsx';
123
+ return path.join(absoluteOutput, `${componentName}.${ext}`);
124
+ }
125
+ /**
126
+ * Babel Plugin for SVGER-CLI
127
+ *
128
+ * This plugin processes SVG files and transforms SVG imports to component imports.
129
+ * It can run in two modes:
130
+ * - Pre-build: Process all SVGs before Babel transformation
131
+ * - On-demand: Transform SVG imports as they're encountered
132
+ */
133
+ export function svgerBabelPlugin(api, options = {}) {
134
+ const config = configService.readConfig();
135
+ const pluginOptions = {
136
+ source: options.source || config.source || './src/icons',
137
+ output: options.output || config.output || './src/components/icons',
138
+ framework: options.framework || config.framework || 'react',
139
+ typescript: options.typescript !== undefined ? options.typescript : config.typescript,
140
+ config: options.config || {},
141
+ include: options.include || ['**/*.svg'],
142
+ exclude: options.exclude || ['node_modules/**'],
143
+ transformImports: options.transformImports !== undefined ? options.transformImports : true,
144
+ processOnInit: options.processOnInit !== undefined ? options.processOnInit : true,
145
+ generateIndex: options.generateIndex !== undefined ? options.generateIndex : true,
146
+ };
147
+ const processedFiles = new Set();
148
+ let initialized = false;
149
+ return {
150
+ name: PLUGIN_NAME,
151
+ // Babel visitor pattern
152
+ visitor: {
153
+ // Process before any transformations if enabled
154
+ Program: {
155
+ enter: async () => {
156
+ if (!initialized && pluginOptions.processOnInit) {
157
+ initialized = true;
158
+ logger.info('SVGER Babel Plugin: Processing SVG files...');
159
+ const results = await processAllSVGs(pluginOptions, processedFiles);
160
+ const successCount = results.filter(r => r.success).length;
161
+ if (successCount > 0) {
162
+ logger.info(`SVGER Babel Plugin: Processed ${successCount} SVG files`);
163
+ }
164
+ }
165
+ },
166
+ },
167
+ // Transform import declarations
168
+ ImportDeclaration(nodePath) {
169
+ if (!pluginOptions.transformImports)
170
+ return;
171
+ const source = nodePath.node.source.value;
172
+ if (typeof source === 'string' && source.endsWith('.svg')) {
173
+ const newPath = transformSVGImport(source, pluginOptions);
174
+ if (newPath) {
175
+ // Replace the import source
176
+ nodePath.node.source.value = newPath.replace(/\.(tsx|jsx)$/, '');
177
+ logger.debug(`SVGER Babel Plugin: Transformed ${source} -> ${newPath}`);
178
+ }
179
+ }
180
+ },
181
+ // Handle dynamic imports
182
+ CallExpression(nodePath) {
183
+ if (!pluginOptions.transformImports)
184
+ return;
185
+ const callee = nodePath.node.callee;
186
+ // Check for import() calls
187
+ if (callee.type === 'Import') {
188
+ const args = nodePath.node.arguments;
189
+ if (args.length > 0 && args[0].type === 'StringLiteral') {
190
+ const source = args[0].value;
191
+ if (source.endsWith('.svg')) {
192
+ const newPath = transformSVGImport(source, pluginOptions);
193
+ if (newPath) {
194
+ args[0].value = newPath.replace(/\.(tsx|jsx)$/, '');
195
+ logger.debug(`SVGER Babel Plugin: Transformed dynamic import ${source} -> ${newPath}`);
196
+ }
197
+ }
198
+ }
199
+ }
200
+ },
201
+ },
202
+ };
203
+ }
204
+ /**
205
+ * Create a Babel plugin instance with preset options
206
+ *
207
+ * @example
208
+ * ```js
209
+ * const plugin = createBabelPlugin({
210
+ * source: './icons',
211
+ * framework: 'react'
212
+ * });
213
+ * ```
214
+ */
215
+ export function createBabelPlugin(options = {}) {
216
+ return (api) => svgerBabelPlugin(api, options);
217
+ }
218
+ /**
219
+ * Default export for convenient usage
220
+ */
221
+ export default svgerBabelPlugin;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Official Jest Preset for SVGER-CLI
3
+ *
4
+ * Provides Jest transformers and configuration for testing SVG components
5
+ * with full framework support.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * // jest.config.js
10
+ * module.exports = {
11
+ * preset: 'svger-cli/jest',
12
+ * // or manually configure:
13
+ * transform: {
14
+ * '\\.svg$': 'svger-cli/jest-transformer'
15
+ * }
16
+ * };
17
+ * ```
18
+ */
19
+ import type { JestPresetOptions } from '../types/integrations.js';
20
+ /**
21
+ * Jest transformer for SVG files
22
+ */
23
+ export declare const svgerJestTransformer: {
24
+ process(sourceText: string, sourcePath: string, options: any): {
25
+ code: string;
26
+ };
27
+ };
28
+ /**
29
+ * Jest preset configuration
30
+ */
31
+ export declare const jestPreset: {
32
+ transform: {
33
+ '\\.svg$': {}[];
34
+ };
35
+ moduleNameMapper: {
36
+ '\\.svg$': string;
37
+ };
38
+ transformIgnorePatterns: string[];
39
+ };
40
+ /**
41
+ * Create custom Jest transformer with options
42
+ */
43
+ export declare function createJestTransformer(options?: JestPresetOptions): typeof svgerJestTransformer;
44
+ export default svgerJestTransformer;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Official Jest Preset for SVGER-CLI
3
+ *
4
+ * Provides Jest transformers and configuration for testing SVG components
5
+ * with full framework support.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * // jest.config.js
10
+ * module.exports = {
11
+ * preset: 'svger-cli/jest',
12
+ * // or manually configure:
13
+ * transform: {
14
+ * '\\.svg$': 'svger-cli/jest-transformer'
15
+ * }
16
+ * };
17
+ * ```
18
+ */
19
+ import { svgProcessor } from '../processors/svg-processor.js';
20
+ import { configService } from '../services/config.js';
21
+ /**
22
+ * Jest transformer for SVG files
23
+ */
24
+ export const svgerJestTransformer = {
25
+ process(sourceText, sourcePath, options) {
26
+ const config = configService.readConfig();
27
+ const transformOptions = options?.transformerConfig?.svger || {};
28
+ // Check if we should mock instead of transform
29
+ if (transformOptions.mock) {
30
+ const componentName = svgProcessor.generateComponentName(sourcePath, 'pascal');
31
+ return {
32
+ code: `
33
+ const React = require('react');
34
+ const ${componentName} = (props) => React.createElement('svg', props);
35
+ module.exports = ${componentName};
36
+ module.exports.default = ${componentName};
37
+ `,
38
+ };
39
+ }
40
+ // Transform SVG to component
41
+ const framework = transformOptions.framework || config.framework || 'react';
42
+ const typescript = transformOptions.typescript !== undefined
43
+ ? transformOptions.typescript
44
+ : config.typescript;
45
+ const componentName = svgProcessor.generateComponentName(sourcePath, 'pascal');
46
+ try {
47
+ // Generate component synchronously for Jest
48
+ const component = generateComponentSync(componentName, sourceText, {
49
+ framework,
50
+ typescript,
51
+ defaultWidth: config.defaultWidth,
52
+ defaultHeight: config.defaultHeight,
53
+ defaultFill: config.defaultFill,
54
+ styleRules: config.styleRules || {},
55
+ });
56
+ // Convert to CommonJS for Jest
57
+ const commonJsCode = convertToCommonJS(component, componentName);
58
+ return {
59
+ code: commonJsCode,
60
+ };
61
+ }
62
+ catch (error) {
63
+ // Return a simple mock on error
64
+ return {
65
+ code: `
66
+ const React = require('react');
67
+ const ${componentName} = (props) => React.createElement('svg', props);
68
+ module.exports = ${componentName};
69
+ module.exports.default = ${componentName};
70
+ `,
71
+ };
72
+ }
73
+ },
74
+ };
75
+ /**
76
+ * Generate component synchronously (for Jest compatibility)
77
+ */
78
+ function generateComponentSync(componentName, svgContent, options) {
79
+ // Clean SVG content
80
+ const cleanedContent = svgProcessor.cleanSVGContent(svgContent);
81
+ // For Jest, we'll generate a simple React component
82
+ const viewBox = svgProcessor.extractViewBox(svgContent);
83
+ const template = `
84
+ import React from 'react';
85
+
86
+ interface ${componentName}Props {
87
+ width?: number | string;
88
+ height?: number | string;
89
+ fill?: string;
90
+ className?: string;
91
+ style?: React.CSSProperties;
92
+ }
93
+
94
+ const ${componentName}: React.FC<${componentName}Props> = ({
95
+ width = ${options.defaultWidth || 24},
96
+ height = ${options.defaultHeight || 24},
97
+ fill = '${options.defaultFill || 'currentColor'}',
98
+ className,
99
+ style,
100
+ ...props
101
+ }) => (
102
+ <svg
103
+ width={width}
104
+ height={height}
105
+ viewBox="${viewBox || '0 0 24 24'}"
106
+ fill={fill}
107
+ className={className}
108
+ style={style}
109
+ {...props}
110
+ >
111
+ ${cleanedContent}
112
+ </svg>
113
+ );
114
+
115
+ export default ${componentName};
116
+ `;
117
+ return template.trim();
118
+ }
119
+ /**
120
+ * Convert ES modules to CommonJS for Jest
121
+ */
122
+ function convertToCommonJS(code, componentName) {
123
+ // Simple conversion for Jest compatibility
124
+ let commonJsCode = code
125
+ .replace(/import\s+React\s+from\s+['"]react['"]/g, "const React = require('react')")
126
+ .replace(/export\s+default\s+/g, 'module.exports = ')
127
+ .replace(/export\s+{([^}]+)}/g, (match, exports) => {
128
+ const exportList = exports.split(',').map((e) => e.trim());
129
+ return exportList
130
+ .map((exp) => `module.exports.${exp} = ${exp}`)
131
+ .join(';');
132
+ });
133
+ // Ensure default export
134
+ if (!commonJsCode.includes('module.exports')) {
135
+ commonJsCode += `\nmodule.exports = ${componentName};`;
136
+ }
137
+ // Also add named export
138
+ commonJsCode += `\nmodule.exports.default = module.exports;`;
139
+ return commonJsCode;
140
+ }
141
+ /**
142
+ * Jest preset configuration
143
+ */
144
+ export const jestPreset = {
145
+ transform: {
146
+ '\\.svg$': ['svger-cli/jest-transformer', {}],
147
+ },
148
+ moduleNameMapper: {
149
+ '\\.svg$': 'svger-cli/jest-transformer',
150
+ },
151
+ transformIgnorePatterns: ['node_modules/(?!(svger-cli)/)'],
152
+ };
153
+ /**
154
+ * Create custom Jest transformer with options
155
+ */
156
+ export function createJestTransformer(options = {}) {
157
+ return {
158
+ process(sourceText, sourcePath, jestOptions) {
159
+ return svgerJestTransformer.process(sourceText, sourcePath, {
160
+ ...jestOptions,
161
+ transformerConfig: {
162
+ svger: options,
163
+ },
164
+ });
165
+ },
166
+ };
167
+ }
168
+ // Default exports
169
+ export default svgerJestTransformer;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Official Next.js Plugin for SVGER-CLI
3
+ *
4
+ * Automatically converts SVG files to framework components in Next.js applications
5
+ * with full SSR support, HMR, and webpack integration.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * // next.config.js
10
+ * const { withSvger } = require('svger-cli/nextjs');
11
+ *
12
+ * module.exports = withSvger({
13
+ * svger: {
14
+ * source: './src/icons',
15
+ * output: './src/components/icons',
16
+ * framework: 'react',
17
+ * typescript: true
18
+ * },
19
+ * // ... other Next.js config
20
+ * });
21
+ * ```
22
+ */
23
+ import { SvgerWebpackPlugin } from './webpack.js';
24
+ import type { NextJsPluginOptions } from '../types/integrations.js';
25
+ /**
26
+ * Next.js plugin configuration wrapper
27
+ */
28
+ export declare function withSvger(nextConfig?: any): any;
29
+ /**
30
+ * Standalone Next.js webpack plugin
31
+ * Can be used directly in next.config.js webpack function
32
+ */
33
+ export declare class SvgerNextJsPlugin extends SvgerWebpackPlugin {
34
+ constructor(options?: NextJsPluginOptions);
35
+ }
36
+ /**
37
+ * Helper function to configure SVG imports in Next.js
38
+ * For use in next.config.js
39
+ *
40
+ * @example
41
+ * ```js
42
+ * const { configureSvgImports } = require('svger-cli/nextjs');
43
+ *
44
+ * module.exports = {
45
+ * webpack(config, options) {
46
+ * configureSvgImports(config, {
47
+ * framework: 'react',
48
+ * typescript: true
49
+ * });
50
+ * return config;
51
+ * }
52
+ * };
53
+ * ```
54
+ */
55
+ export declare function configureSvgImports(webpackConfig: any, options?: Partial<NextJsPluginOptions>): void;
56
+ export default withSvger;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Official Next.js Plugin for SVGER-CLI
3
+ *
4
+ * Automatically converts SVG files to framework components in Next.js applications
5
+ * with full SSR support, HMR, and webpack integration.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * // next.config.js
10
+ * const { withSvger } = require('svger-cli/nextjs');
11
+ *
12
+ * module.exports = withSvger({
13
+ * svger: {
14
+ * source: './src/icons',
15
+ * output: './src/components/icons',
16
+ * framework: 'react',
17
+ * typescript: true
18
+ * },
19
+ * // ... other Next.js config
20
+ * });
21
+ * ```
22
+ */
23
+ import { SvgerWebpackPlugin } from './webpack.js';
24
+ import { logger } from '../core/logger.js';
25
+ /**
26
+ * Next.js plugin configuration wrapper
27
+ */
28
+ export function withSvger(nextConfig = {}) {
29
+ return {
30
+ ...nextConfig,
31
+ webpack(config, options) {
32
+ const { isServer } = options;
33
+ // Get svger options from Next.js config
34
+ const svgerOptions = nextConfig.svger || {};
35
+ // Add SVGER webpack plugin
36
+ if (!config.plugins) {
37
+ config.plugins = [];
38
+ }
39
+ // Only run on client build or if explicitly enabled for SSR
40
+ if (!isServer || svgerOptions.ssr !== false) {
41
+ const pluginInstance = new SvgerWebpackPlugin({
42
+ source: svgerOptions.source,
43
+ output: svgerOptions.output,
44
+ framework: svgerOptions.framework || 'react',
45
+ typescript: svgerOptions.typescript,
46
+ config: svgerOptions.config,
47
+ include: svgerOptions.include,
48
+ exclude: svgerOptions.exclude,
49
+ hmr: svgerOptions.hmr,
50
+ generateIndex: svgerOptions.generateIndex,
51
+ });
52
+ config.plugins.push(pluginInstance);
53
+ if (!isServer) {
54
+ logger.info('SVGER Next.js Plugin: Configured for client build');
55
+ }
56
+ else {
57
+ logger.info('SVGER Next.js Plugin: Configured for server build');
58
+ }
59
+ }
60
+ // Add SVG file handling rule
61
+ config.module.rules.push({
62
+ test: /\.svg$/,
63
+ issuer: /\.[jt]sx?$/,
64
+ use: [
65
+ {
66
+ loader: 'svger-cli/webpack-loader',
67
+ options: {
68
+ framework: svgerOptions.framework || 'react',
69
+ typescript: svgerOptions.typescript,
70
+ },
71
+ },
72
+ ],
73
+ });
74
+ // Call user's custom webpack config if provided
75
+ if (svgerOptions.webpack && typeof svgerOptions.webpack === 'function') {
76
+ return svgerOptions.webpack(config, options);
77
+ }
78
+ // Call original webpack config if provided
79
+ if (typeof nextConfig.webpack === 'function') {
80
+ return nextConfig.webpack(config, options);
81
+ }
82
+ return config;
83
+ },
84
+ };
85
+ }
86
+ /**
87
+ * Standalone Next.js webpack plugin
88
+ * Can be used directly in next.config.js webpack function
89
+ */
90
+ export class SvgerNextJsPlugin extends SvgerWebpackPlugin {
91
+ constructor(options = {}) {
92
+ super({
93
+ source: options.source,
94
+ output: options.output,
95
+ framework: options.framework || 'react',
96
+ typescript: options.typescript,
97
+ config: options.config,
98
+ include: options.include,
99
+ exclude: options.exclude,
100
+ hmr: options.hmr,
101
+ generateIndex: options.generateIndex,
102
+ });
103
+ }
104
+ }
105
+ /**
106
+ * Helper function to configure SVG imports in Next.js
107
+ * For use in next.config.js
108
+ *
109
+ * @example
110
+ * ```js
111
+ * const { configureSvgImports } = require('svger-cli/nextjs');
112
+ *
113
+ * module.exports = {
114
+ * webpack(config, options) {
115
+ * configureSvgImports(config, {
116
+ * framework: 'react',
117
+ * typescript: true
118
+ * });
119
+ * return config;
120
+ * }
121
+ * };
122
+ * ```
123
+ */
124
+ export function configureSvgImports(webpackConfig, options = {}) {
125
+ webpackConfig.module.rules.push({
126
+ test: /\.svg$/,
127
+ issuer: /\.[jt]sx?$/,
128
+ use: [
129
+ {
130
+ loader: 'svger-cli/webpack-loader',
131
+ options: {
132
+ framework: options.framework || 'react',
133
+ typescript: options.typescript !== undefined ? options.typescript : true,
134
+ },
135
+ },
136
+ ],
137
+ });
138
+ }
139
+ // Default export
140
+ export default withSvger;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Official Rollup Plugin for SVGER-CLI
3
+ *
4
+ * Automatically converts SVG files to framework components during Rollup builds
5
+ * with full bundle optimization and tree-shaking support.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * // rollup.config.js
10
+ * import { svgerRollupPlugin } from 'svger-cli/rollup';
11
+ *
12
+ * export default {
13
+ * plugins: [
14
+ * svgerRollupPlugin({
15
+ * source: './src/icons',
16
+ * output: './src/components/icons',
17
+ * framework: 'react',
18
+ * typescript: true
19
+ * })
20
+ * ]
21
+ * };
22
+ * ```
23
+ */
24
+ import type { RollupPluginOptions } from '../types/integrations.js';
25
+ /**
26
+ * Rollup Plugin for SVGER-CLI
27
+ */
28
+ export declare function svgerRollupPlugin(options?: RollupPluginOptions): any;
29
+ export default svgerRollupPlugin;