svgfusion 1.0.0-beta.2 → 1.0.0-beta.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.
package/dist/cli.d.mts CHANGED
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ #!/usr/bin/env node
package/dist/cli.d.ts CHANGED
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ #!/usr/bin/env node
package/dist/cli.js CHANGED
@@ -1,2 +1,91 @@
1
- "use strict";
2
- //# sourceMappingURL=cli.js.map
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var commander = require('commander');
5
+ var promises = require('fs/promises');
6
+ var path = require('path');
7
+ var fs = require('fs');
8
+ var core = require('@svgr/core');
9
+ var svgo = require('svgo');
10
+ var url = require('url');
11
+
12
+ var A=()=>typeof document>"u"?new URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href,u=A();async function R(e){try{return await promises.readFile(e,"utf-8")}catch(t){throw new Error(`Failed to read SVG file: ${e}. ${t}`)}}async function T(e,t){try{await H(path.dirname(e)),await promises.writeFile(e,t,"utf-8");}catch(r){throw new Error(`Failed to write component file: ${e}. ${r}`)}}async function x(e,t=!1){try{let r=await promises.readdir(e),n=[];for(let s of r){let i=path.join(e,s),o=await promises.stat(i);if(o.isDirectory()&&t){let p=await x(i,t);n.push(...p);}else o.isFile()&&path.extname(s).toLowerCase()===".svg"&&n.push(i);}return n}catch(r){throw new Error(`Failed to read directory: ${e}. ${r}`)}}async function H(e){fs.existsSync(e)||await promises.mkdir(e,{recursive:!0});}function d(e,t=!0){return e==="react"?t?".tsx":".jsx":".vue"}function w(e,t,r){return `${t}${r}`}var Q={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:!1,removeTitle:!1,removeDesc:!1,removeUselessStrokeAndFill:!1,convertColors:{currentColor:!0,names2hex:!0,rgb2hex:!0,shorthex:!0,shortname:!0}}}},"removeDimensions","cleanupNumericValues"]};function f(e,t=Q){try{return svgo.optimize(e,t).data}catch(r){throw new Error(`Failed to optimize SVG: ${r}`)}}function C(e){return e.replace(/[^a-zA-Z0-9\s-_]/g," ").split(/[\s-_]+/).filter(t=>t.length>0).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function $(e,t,r){let n=t?C(t):"",s=r?C(r):"",i=C(e);return `${n}${i}${s}`}async function z(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,memo:p=!0,ref:m=!0,titleProp:l=!0,descProp:g=!0}=t;try{let a=e;i&&(a=f(e));let c=$(r||"icon",n,s),v=await core.transform(a,{typescript:o,memo:p,ref:m,titleProp:l,descProp:g,svgProps:{className:"{className}"}},{componentName:c}),h=o?`import { SVGProps } from 'react';
13
+ `:"",y=p?`import { memo } from 'react';
14
+ `:"",S=m?`import { forwardRef } from 'react';
15
+ `:"",D=`
16
+ export default ${c};
17
+ export { ${c} };`,G=o?"SVGProps<SVGSVGElement> & { className?: string; }":"",N=o?`props: ${G}`:"props",k=p?"memo(":"",_=m?`forwardRef<SVGSVGElement, ${G}>(`:"";v=`${h}${y}${S}
18
+ const ${c} = ${k}${_}(${N}) => {
19
+ return ${v};
20
+ }${`${m?")":""}${p?")":""}`};
21
+
22
+ ${c}.displayName = "${c}";
23
+ ${D}`;let O=d("react",o),j=w("icon.svg",c,O);return {code:v,filename:j,componentName:c}}catch(a){throw new Error(`Failed to convert SVG to React: ${a}`)}}function E(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,compositionApi:p=!0,scriptSetup:m=!0}=t;try{let l=e;i&&(l=f(e));let a=$(r||"icon",n,s),F=l.replace(/<\?xml[^>]*\?>\s*/,"").replace(/xmlns="[^"]*"/g,"").replace(/width="[^"]*"/g,"").replace(/height="[^"]*"/g,"").replace(/<svg/,'<svg v-bind="$attrs"').replace(/class="([^"]*)"/g,'class="$1"').replace(/currentColor/g,"currentColor"),c=m?Y(o,a):ee(a,o),b=`<template>
24
+ ${F}
25
+ </template>`,h=`${c}
26
+
27
+ ${b}
28
+
29
+ <style scoped>
30
+ /* Add component-specific styles here */
31
+ </style>`,y=d("vue",o),S=w("icon.svg",a,y);return {code:h,filename:S,componentName:a}}catch(l){throw new Error(`Failed to convert SVG to Vue: ${l}`)}}function Y(e,t){return `<script setup${e?' lang="ts"':""}>${e?`
32
+ interface Props {
33
+ class?: string;
34
+ style?: string | Record<string, any>;
35
+ }`:""}${e?`
36
+ const props = withDefaults(defineProps<Props>(), {
37
+ class: '',
38
+ style: undefined,
39
+ });`:`
40
+ const props = withDefaults(defineProps(), {
41
+ class: '',
42
+ style: undefined,
43
+ });`}
44
+
45
+ // Component name for debugging
46
+ const __name = '${t}';
47
+ </script>`}function ee(e,t){let r=t?' lang="ts"':"",n=t?`
48
+ interface Props {
49
+ class?: string;
50
+ style?: string | Record<string, any>;
51
+ }`:"",s=t?`
52
+ const ${e} = defineComponent({
53
+ name: '${e}',
54
+ props: {
55
+ class: {
56
+ type: String,
57
+ default: '',
58
+ },
59
+ style: {
60
+ type: [String, Object],
61
+ default: undefined,
62
+ },
63
+ },
64
+ setup(props: Props) {
65
+ return {};
66
+ },
67
+ });
68
+
69
+ export default ${e};
70
+ export { ${e} };`:`
71
+ const ${e} = defineComponent({
72
+ name: '${e}',
73
+ props: {
74
+ class: {
75
+ type: String,
76
+ default: '',
77
+ },
78
+ style: {
79
+ type: [String, Object],
80
+ default: undefined,
81
+ },
82
+ },
83
+ setup(props) {
84
+ return {};
85
+ },
86
+ });
87
+
88
+ export default ${e};
89
+ export { ${e} };`;return `<script${r}>
90
+ import { defineComponent } from 'vue';${n}${s}
91
+ </script>`}var se=url.fileURLToPath(u),ie=path.dirname(se),ae=JSON.parse(fs.readFileSync(path.join(ie,"..","package.json"),"utf-8")),V=new commander.Command;V.name("svgfusion").description("Transform SVG files into production-ready React and Vue 3 components").version(ae.version);V.command("convert").description("Convert SVG files to React or Vue components").argument("<input>","Input SVG file or directory").option("-o, --output <output>","Output directory","./components").option("-f, --framework <framework>","Target framework (react|vue)","react").option("-t, --typescript","Generate TypeScript files",!1).option("--no-optimize","Skip SVG optimization").action(async(e,t)=>{console.log("\u{1F504} Processing SVG files...");try{let{framework:r,output:n,typescript:s,optimize:i}=t;if(r!=="react"&&r!=="vue")throw new Error('Framework must be either "react" or "vue"');let o=await x(e);if(o.length===0)throw new Error("No SVG files found in the input path");console.log(`\u{1F504} Converting ${o.length} SVG file(s)...`);for(let p of o){let m=await R(p),l=i?f(m):m,g=r==="react"?await z(l,{typescript:s}):E(l,{typescript:s}),a=path.join(n,g.filename);await T(a,g.code);}console.log(`\u2705 Successfully converted ${o.length} SVG file(s) to ${r} components`);}catch(r){console.error(`\u274C Error: ${r instanceof Error?r.message:"Unknown error"}`),process.exit(1);}});V.parse();
package/dist/cli.mjs CHANGED
@@ -1 +1,89 @@
1
- //# sourceMappingURL=cli.mjs.map
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';
4
+ import { dirname, join, extname } from 'path';
5
+ import { readFileSync, existsSync } from 'fs';
6
+ import { transform } from '@svgr/core';
7
+ import { optimize } from 'svgo';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ async function z(e){try{return await readFile(e,"utf-8")}catch(t){throw new Error(`Failed to read SVG file: ${e}. ${t}`)}}async function E(e,t){try{await H(dirname(e)),await writeFile(e,t,"utf-8");}catch(r){throw new Error(`Failed to write component file: ${e}. ${r}`)}}async function C(e,t=!1){try{let r=await readdir(e),n=[];for(let s of r){let i=join(e,s),o=await stat(i);if(o.isDirectory()&&t){let p=await C(i,t);n.push(...p);}else o.isFile()&&extname(s).toLowerCase()===".svg"&&n.push(i);}return n}catch(r){throw new Error(`Failed to read directory: ${e}. ${r}`)}}async function H(e){existsSync(e)||await mkdir(e,{recursive:!0});}function $(e,t=!0){return e==="react"?t?".tsx":".jsx":".vue"}function w(e,t,r){return `${t}${r}`}var Q={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:!1,removeTitle:!1,removeDesc:!1,removeUselessStrokeAndFill:!1,convertColors:{currentColor:!0,names2hex:!0,rgb2hex:!0,shorthex:!0,shortname:!0}}}},"removeDimensions","cleanupNumericValues"]};function u(e,t=Q){try{return optimize(e,t).data}catch(r){throw new Error(`Failed to optimize SVG: ${r}`)}}function V(e){return e.replace(/[^a-zA-Z0-9\s-_]/g," ").split(/[\s-_]+/).filter(t=>t.length>0).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function h(e,t,r){let n=t?V(t):"",s=r?V(r):"",i=V(e);return `${n}${i}${s}`}async function P(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,memo:p=!0,ref:m=!0,titleProp:l=!0,descProp:f=!0}=t;try{let a=e;i&&(a=u(e));let c=h(r||"icon",n,s),g=await transform(a,{typescript:o,memo:p,ref:m,titleProp:l,descProp:f,svgProps:{className:"{className}"}},{componentName:c}),y=o?`import { SVGProps } from 'react';
11
+ `:"",S=p?`import { memo } from 'react';
12
+ `:"",x=m?`import { forwardRef } from 'react';
13
+ `:"",N=`
14
+ export default ${c};
15
+ export { ${c} };`,T=o?"SVGProps<SVGSVGElement> & { className?: string; }":"",k=o?`props: ${T}`:"props",O=p?"memo(":"",_=m?`forwardRef<SVGSVGElement, ${T}>(`:"";g=`${y}${S}${x}
16
+ const ${c} = ${O}${_}(${k}) => {
17
+ return ${g};
18
+ }${`${m?")":""}${p?")":""}`};
19
+
20
+ ${c}.displayName = "${c}";
21
+ ${N}`;let A=$("react",o),j=w("icon.svg",c,A);return {code:g,filename:j,componentName:c}}catch(a){throw new Error(`Failed to convert SVG to React: ${a}`)}}function R(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,compositionApi:p=!0,scriptSetup:m=!0}=t;try{let l=e;i&&(l=u(e));let a=h(r||"icon",n,s),b=l.replace(/<\?xml[^>]*\?>\s*/,"").replace(/xmlns="[^"]*"/g,"").replace(/width="[^"]*"/g,"").replace(/height="[^"]*"/g,"").replace(/<svg/,'<svg v-bind="$attrs"').replace(/class="([^"]*)"/g,'class="$1"').replace(/currentColor/g,"currentColor"),c=m?Y(o,a):ee(a,o),G=`<template>
22
+ ${b}
23
+ </template>`,y=`${c}
24
+
25
+ ${G}
26
+
27
+ <style scoped>
28
+ /* Add component-specific styles here */
29
+ </style>`,S=$("vue",o),x=w("icon.svg",a,S);return {code:y,filename:x,componentName:a}}catch(l){throw new Error(`Failed to convert SVG to Vue: ${l}`)}}function Y(e,t){return `<script setup${e?' lang="ts"':""}>${e?`
30
+ interface Props {
31
+ class?: string;
32
+ style?: string | Record<string, any>;
33
+ }`:""}${e?`
34
+ const props = withDefaults(defineProps<Props>(), {
35
+ class: '',
36
+ style: undefined,
37
+ });`:`
38
+ const props = withDefaults(defineProps(), {
39
+ class: '',
40
+ style: undefined,
41
+ });`}
42
+
43
+ // Component name for debugging
44
+ const __name = '${t}';
45
+ </script>`}function ee(e,t){let r=t?' lang="ts"':"",n=t?`
46
+ interface Props {
47
+ class?: string;
48
+ style?: string | Record<string, any>;
49
+ }`:"",s=t?`
50
+ const ${e} = defineComponent({
51
+ name: '${e}',
52
+ props: {
53
+ class: {
54
+ type: String,
55
+ default: '',
56
+ },
57
+ style: {
58
+ type: [String, Object],
59
+ default: undefined,
60
+ },
61
+ },
62
+ setup(props: Props) {
63
+ return {};
64
+ },
65
+ });
66
+
67
+ export default ${e};
68
+ export { ${e} };`:`
69
+ const ${e} = defineComponent({
70
+ name: '${e}',
71
+ props: {
72
+ class: {
73
+ type: String,
74
+ default: '',
75
+ },
76
+ style: {
77
+ type: [String, Object],
78
+ default: undefined,
79
+ },
80
+ },
81
+ setup(props) {
82
+ return {};
83
+ },
84
+ });
85
+
86
+ export default ${e};
87
+ export { ${e} };`;return `<script${r}>
88
+ import { defineComponent } from 'vue';${n}${s}
89
+ </script>`}var se=fileURLToPath(import.meta.url),ie=dirname(se),ae=JSON.parse(readFileSync(join(ie,"..","package.json"),"utf-8")),F=new Command;F.name("svgfusion").description("Transform SVG files into production-ready React and Vue 3 components").version(ae.version);F.command("convert").description("Convert SVG files to React or Vue components").argument("<input>","Input SVG file or directory").option("-o, --output <output>","Output directory","./components").option("-f, --framework <framework>","Target framework (react|vue)","react").option("-t, --typescript","Generate TypeScript files",!1).option("--no-optimize","Skip SVG optimization").action(async(e,t)=>{console.log("\u{1F504} Processing SVG files...");try{let{framework:r,output:n,typescript:s,optimize:i}=t;if(r!=="react"&&r!=="vue")throw new Error('Framework must be either "react" or "vue"');let o=await C(e);if(o.length===0)throw new Error("No SVG files found in the input path");console.log(`\u{1F504} Converting ${o.length} SVG file(s)...`);for(let p of o){let m=await z(p),l=i?u(m):m,f=r==="react"?await P(l,{typescript:s}):R(l,{typescript:s}),a=join(n,f.filename);await E(a,f.code);}console.log(`\u2705 Successfully converted ${o.length} SVG file(s) to ${r} components`);}catch(r){console.error(`\u274C Error: ${r instanceof Error?r.message:"Unknown error"}`),process.exit(1);}});F.parse();
package/dist/index.js CHANGED
@@ -1,359 +1,53 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
19
2
 
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- convertToReact: () => convertToReact,
24
- convertToVue: () => convertToVue,
25
- createSvgoConfig: () => createSvgoConfig,
26
- formatComponentName: () => formatComponentName,
27
- optimizeSvg: () => optimizeSvg,
28
- pascalCase: () => pascalCase,
29
- readSvgDirectory: () => readSvgDirectory,
30
- readSvgFile: () => readSvgFile,
31
- sanitizeComponentName: () => sanitizeComponentName,
32
- svgToComponentName: () => svgToComponentName,
33
- writeComponentFile: () => writeComponentFile,
34
- writeSvgFile: () => writeSvgFile
35
- });
36
- module.exports = __toCommonJS(src_exports);
37
-
38
- // src/converters/react.ts
39
- var import_core = require("@svgr/core");
40
-
41
- // src/utils/svgo.ts
42
- var import_svgo = require("svgo");
43
- var defaultConfig = {
44
- plugins: [
45
- {
46
- name: "preset-default",
47
- params: {
48
- overrides: {
49
- removeViewBox: false,
50
- removeTitle: false,
51
- removeDesc: false,
52
- removeUselessStrokeAndFill: false,
53
- convertColors: {
54
- currentColor: true,
55
- names2hex: true,
56
- rgb2hex: true,
57
- shorthex: true,
58
- // cspell:disable-line
59
- shortname: true
60
- }
61
- }
62
- }
63
- },
64
- "removeDimensions",
65
- "cleanupNumericValues"
66
- ]
67
- };
68
- function optimizeSvg(svgContent, config = defaultConfig) {
69
- try {
70
- const result = (0, import_svgo.optimize)(svgContent, config);
71
- return result.data;
72
- } catch (error) {
73
- throw new Error(`Failed to optimize SVG: ${error}`);
74
- }
75
- }
76
- function createSvgoConfig(options) {
77
- const plugins = [
78
- {
79
- name: "preset-default",
80
- params: {
81
- overrides: {
82
- removeViewBox: !options.removeViewBox,
83
- removeTitle: !options.removeTitle,
84
- removeDesc: !options.removeDesc,
85
- removeUselessStrokeAndFill: !options.preserveClasses,
86
- convertColors: options.preserveColors ? false : {
87
- currentColor: true,
88
- names2hex: true,
89
- rgb2hex: true,
90
- shorthex: true,
91
- // cspell:disable-line
92
- shortname: true
93
- }
94
- }
95
- }
96
- },
97
- "cleanupNumericValues"
98
- ];
99
- if (options.removeDimensions !== false) {
100
- plugins.push("removeDimensions");
101
- }
102
- return { plugins };
103
- }
3
+ var core = require('@svgr/core');
4
+ var svgo = require('svgo');
5
+ var promises = require('fs/promises');
6
+ var path = require('path');
7
+ var fs = require('fs');
104
8
 
105
- // src/utils/name.ts
106
- function svgToComponentName(filename) {
107
- let baseName = filename.replace(/\.svg$/i, "");
108
- baseName = processComplexFilename(baseName);
109
- return pascalCase(baseName);
110
- }
111
- function processComplexFilename(filename) {
112
- let processed = filename;
113
- const simpleMatch = processed.match(/^([^,]+),\s*Type=([^,]+)/i);
114
- if (simpleMatch) {
115
- processed = `${simpleMatch[1]} ${simpleMatch[2]}`;
116
- return processed;
117
- }
118
- const sizeMatch = processed.match(/Size=(\w+)/i);
119
- const colorMatch = processed.match(/Color=(\w+)/i);
120
- const typeMatch = processed.match(/Type=(\w+)/i);
121
- if (sizeMatch || colorMatch || typeMatch) {
122
- const parts = [];
123
- if (typeMatch)
124
- parts.push(typeMatch[1]);
125
- if (colorMatch)
126
- parts.push(colorMatch[1]);
127
- if (sizeMatch)
128
- parts.push(sizeMatch[1]);
129
- if (parts.length > 0) {
130
- processed = parts.join(" ");
131
- return processed;
132
- }
133
- }
134
- processed = processed.replace(/\b\w+=\w+\b/g, "").replace(/,\s*/g, " ").replace(/[=]/g, " ").replace(/\s+/g, " ").trim();
135
- if (!processed || processed.length < 2) {
136
- processed = filename;
137
- }
138
- return processed;
139
- }
140
- function sanitizeComponentName(name) {
141
- return pascalCase(name.replace(/[^a-zA-Z0-9]/g, " "));
142
- }
143
- function pascalCase(str) {
144
- return str.replace(/[^a-zA-Z0-9\s-_]/g, " ").split(/[\s-_]+/).filter((word) => word.length > 0).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
145
- }
146
- function formatComponentName(name, prefix, suffix) {
147
- const prefixPart = prefix ? pascalCase(prefix) : "";
148
- const suffixPart = suffix ? pascalCase(suffix) : "";
149
- const baseName = pascalCase(name);
150
- return `${prefixPart}${baseName}${suffixPart}`;
151
- }
9
+ var j={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:!1,removeTitle:!1,removeDesc:!1,removeUselessStrokeAndFill:!1,convertColors:{currentColor:!0,names2hex:!0,rgb2hex:!0,shorthex:!0,shortname:!0}}}},"removeDimensions","cleanupNumericValues"]};function g(e,t=j){try{return svgo.optimize(e,t).data}catch(r){throw new Error(`Failed to optimize SVG: ${r}`)}}function B(e){let t=[{name:"preset-default",params:{overrides:{removeViewBox:!e.removeViewBox,removeTitle:!e.removeTitle,removeDesc:!e.removeDesc,removeUselessStrokeAndFill:!e.preserveClasses,convertColors:e.preserveColors?!1:{currentColor:!0,names2hex:!0,rgb2hex:!0,shorthex:!0,shortname:!0}}}},"cleanupNumericValues"];return e.removeDimensions!==!1&&t.push("removeDimensions"),{plugins:t}}function _(e){let t=e.replace(/\.svg$/i,"");return t=k(t),u(t)}function k(e){let t=e,r=t.match(/^([^,]+),\s*Type=([^,]+)/i);if(r)return t=`${r[1]} ${r[2]}`,t;let n=t.match(/Size=(\w+)/i),s=t.match(/Color=(\w+)/i),i=t.match(/Type=(\w+)/i);if(n||s||i){let o=[];if(i&&o.push(i[1]),s&&o.push(s[1]),n&&o.push(n[1]),o.length>0)return t=o.join(" "),t}return t=t.replace(/\b\w+=\w+\b/g,"").replace(/,\s*/g," ").replace(/[=]/g," ").replace(/\s+/g," ").trim(),(!t||t.length<2)&&(t=e),t}function M(e){return u(e.replace(/[^a-zA-Z0-9]/g," "))}function u(e){return e.replace(/[^a-zA-Z0-9\s-_]/g," ").split(/[\s-_]+/).filter(t=>t.length>0).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function v(e,t,r){let n=t?u(t):"",s=r?u(r):"",i=u(e);return `${n}${i}${s}`}async function J(e){try{return await promises.readFile(e,"utf-8")}catch(t){throw new Error(`Failed to read SVG file: ${e}. ${t}`)}}async function K(e,t){try{await D(path.dirname(e)),await promises.writeFile(e,t,"utf-8");}catch(r){throw new Error(`Failed to write SVG file: ${e}. ${r}`)}}async function Q(e,t){try{await D(path.dirname(e)),await promises.writeFile(e,t,"utf-8");}catch(r){throw new Error(`Failed to write component file: ${e}. ${r}`)}}async function T(e,t=!1){try{let r=await promises.readdir(e),n=[];for(let s of r){let i=path.join(e,s),o=await promises.stat(i);if(o.isDirectory()&&t){let c=await T(i,t);n.push(...c);}else o.isFile()&&path.extname(s).toLowerCase()===".svg"&&n.push(i);}return n}catch(r){throw new Error(`Failed to read directory: ${e}. ${r}`)}}async function D(e){fs.existsSync(e)||await promises.mkdir(e,{recursive:!0});}function C(e,t=!0){return e==="react"?t?".tsx":".jsx":".vue"}function $(e,t,r){return `${t}${r}`}async function Y(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,memo:c=!0,ref:l=!0,titleProp:m=!0,descProp:h=!0}=t;try{let p=e;i&&(p=g(e));let a=v(r||"icon",n,s),d=await core.transform(p,{typescript:o,memo:c,ref:l,titleProp:m,descProp:h,svgProps:{className:"{className}"}},{componentName:a}),x=o?`import { SVGProps } from 'react';
10
+ `:"",w=c?`import { memo } from 'react';
11
+ `:"",y=l?`import { forwardRef } from 'react';
12
+ `:"",N=`
13
+ export default ${a};
14
+ export { ${a} };`,b=o?"SVGProps<SVGSVGElement> & { className?: string; }":"",z=o?`props: ${b}`:"props",E=c?"memo(":"",O=l?`forwardRef<SVGSVGElement, ${b}>(`:"";d=`${x}${w}${y}
15
+ const ${a} = ${E}${O}(${z}) => {
16
+ return ${d};
17
+ }${`${l?")":""}${c?")":""}`};
152
18
 
153
- // src/utils/files.ts
154
- var import_promises = require("fs/promises");
155
- var import_path = require("path");
156
- var import_fs = require("fs");
157
- async function readSvgFile(filePath) {
158
- try {
159
- const content = await (0, import_promises.readFile)(filePath, "utf-8");
160
- return content;
161
- } catch (error) {
162
- throw new Error(`Failed to read SVG file: ${filePath}. ${error}`);
163
- }
164
- }
165
- async function writeSvgFile(filePath, content) {
166
- try {
167
- await ensureDirectoryExists((0, import_path.dirname)(filePath));
168
- await (0, import_promises.writeFile)(filePath, content, "utf-8");
169
- } catch (error) {
170
- throw new Error(`Failed to write SVG file: ${filePath}. ${error}`);
171
- }
172
- }
173
- async function writeComponentFile(filePath, content) {
174
- try {
175
- await ensureDirectoryExists((0, import_path.dirname)(filePath));
176
- await (0, import_promises.writeFile)(filePath, content, "utf-8");
177
- } catch (error) {
178
- throw new Error(`Failed to write component file: ${filePath}. ${error}`);
179
- }
180
- }
181
- async function readSvgDirectory(dirPath, recursive = false) {
182
- try {
183
- const files = await (0, import_promises.readdir)(dirPath);
184
- const svgFiles = [];
185
- for (const file of files) {
186
- const filePath = (0, import_path.join)(dirPath, file);
187
- const fileStat = await (0, import_promises.stat)(filePath);
188
- if (fileStat.isDirectory() && recursive) {
189
- const nestedFiles = await readSvgDirectory(filePath, recursive);
190
- svgFiles.push(...nestedFiles);
191
- } else if (fileStat.isFile() && (0, import_path.extname)(file).toLowerCase() === ".svg") {
192
- svgFiles.push(filePath);
193
- }
194
- }
195
- return svgFiles;
196
- } catch (error) {
197
- throw new Error(`Failed to read directory: ${dirPath}. ${error}`);
198
- }
199
- }
200
- async function ensureDirectoryExists(dirPath) {
201
- if (!(0, import_fs.existsSync)(dirPath)) {
202
- await (0, import_promises.mkdir)(dirPath, { recursive: true });
203
- }
204
- }
205
- function getFileExtension(framework, typescript = true) {
206
- if (framework === "react") {
207
- return typescript ? ".tsx" : ".jsx";
208
- } else {
209
- return typescript ? ".vue" : ".vue";
210
- }
211
- }
212
- function getComponentFilename(_svgFilename, componentName, extension) {
213
- return `${componentName}${extension}`;
214
- }
19
+ ${a}.displayName = "${a}";
20
+ ${N}`;let P=C("react",o),G=$("icon.svg",a,P);return {code:d,filename:G,componentName:a}}catch(p){throw new Error(`Failed to convert SVG to React: ${p}`)}}function ee(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,compositionApi:c=!0,scriptSetup:l=!0}=t;try{let m=e;i&&(m=g(e));let p=v(r||"icon",n,s),S=m.replace(/<\?xml[^>]*\?>\s*/,"").replace(/xmlns="[^"]*"/g,"").replace(/width="[^"]*"/g,"").replace(/height="[^"]*"/g,"").replace(/<svg/,'<svg v-bind="$attrs"').replace(/class="([^"]*)"/g,'class="$1"').replace(/currentColor/g,"currentColor"),a=l?te(o,p):re(p,o),F=`<template>
21
+ ${S}
22
+ </template>`,x=`${a}
215
23
 
216
- // src/converters/react.ts
217
- async function convertToReact(svgContent, options = {}) {
218
- const {
219
- name,
220
- prefix,
221
- suffix,
222
- optimize: optimize2 = true,
223
- typescript = true,
224
- memo = true,
225
- ref = true,
226
- titleProp = true,
227
- descProp = true
228
- } = options;
229
- try {
230
- let processedSvg = svgContent;
231
- if (optimize2) {
232
- processedSvg = optimizeSvg(svgContent);
233
- }
234
- const baseName = name || "icon";
235
- const componentName = formatComponentName(baseName, prefix, suffix);
236
- const svgrOptions = {
237
- typescript,
238
- memo,
239
- ref,
240
- titleProp,
241
- descProp,
242
- svgProps: {
243
- className: "{className}"
244
- }
245
- };
246
- let result = await (0, import_core.transform)(processedSvg, svgrOptions, {
247
- componentName
248
- });
249
- const typeImports = typescript ? `import { SVGProps } from 'react';
250
- ` : "";
251
- const memoImport = memo ? `import { memo } from 'react';
252
- ` : "";
253
- const refImport = ref ? `import { forwardRef } from 'react';
254
- ` : "";
255
- const exports = `
256
- export default ${componentName};
257
- export { ${componentName} };`;
258
- const propsType = typescript ? `SVGProps<SVGSVGElement> & { className?: string; }` : "";
259
- const componentProps = typescript ? `props: ${propsType}` : "props";
260
- const componentFunc = memo ? `memo(` : "";
261
- const refWrapper = ref ? `forwardRef<SVGSVGElement, ${propsType}>(` : "";
262
- const closingWrappers = `${ref ? ")" : ""}${memo ? ")" : ""}`;
263
- result = `${typeImports}${memoImport}${refImport}
264
- const ${componentName} = ${componentFunc}${refWrapper}(${componentProps}) => {
265
- return ${result};
266
- }${closingWrappers};
24
+ ${F}
267
25
 
268
- ${componentName}.displayName = "${componentName}";
269
- ${exports}`;
270
- const extension = getFileExtension("react", typescript);
271
- const filename = getComponentFilename("icon.svg", componentName, extension);
272
- return {
273
- code: result,
274
- filename,
275
- componentName
276
- };
277
- } catch (error) {
278
- throw new Error(`Failed to convert SVG to React: ${error}`);
279
- }
280
- }
281
-
282
- // src/converters/vue.ts
283
- function convertToVue(svgContent, options = {}) {
284
- const {
285
- name,
286
- prefix,
287
- suffix,
288
- optimize: optimize2 = true,
289
- typescript = true,
290
- compositionApi: _compositionApi = true,
291
- // eslint-disable-line @typescript-eslint/no-unused-vars
292
- scriptSetup = true
293
- } = options;
294
- try {
295
- let processedSvg = svgContent;
296
- if (optimize2) {
297
- processedSvg = optimizeSvg(svgContent);
298
- }
299
- const baseName = name || "icon";
300
- const componentName = formatComponentName(baseName, prefix, suffix);
301
- const cleanedSvg = processedSvg.replace(/<\?xml[^>]*\?>\s*/, "").replace(/xmlns="[^"]*"/g, "").replace(/width="[^"]*"/g, "").replace(/height="[^"]*"/g, "").replace(/<svg/, '<svg v-bind="$attrs"').replace(/class="([^"]*)"/g, 'class="$1"').replace(/currentColor/g, "currentColor");
302
- const scriptTag = scriptSetup ? generateScriptSetup(typescript, componentName) : generateCompositionScript(componentName, typescript);
303
- const template = `<template>
304
- ${cleanedSvg}
305
- </template>`;
306
- const style = `<style scoped>
26
+ <style scoped>
307
27
  /* Add component-specific styles here */
308
- </style>`;
309
- const vueComponent = `${scriptTag}
310
-
311
- ${template}
312
-
313
- ${style}`;
314
- const extension = getFileExtension("vue", typescript);
315
- const filename = getComponentFilename("icon.svg", componentName, extension);
316
- return {
317
- code: vueComponent,
318
- filename,
319
- componentName
320
- };
321
- } catch (error) {
322
- throw new Error(`Failed to convert SVG to Vue: ${error}`);
323
- }
324
- }
325
- function generateScriptSetup(typescript, componentName) {
326
- const lang = typescript ? ' lang="ts"' : "";
327
- const propsType = typescript ? `
28
+ </style>`,w=C("vue",o),y=$("icon.svg",p,w);return {code:x,filename:y,componentName:p}}catch(m){throw new Error(`Failed to convert SVG to Vue: ${m}`)}}function te(e,t){return `<script setup${e?' lang="ts"':""}>${e?`
328
29
  interface Props {
329
30
  class?: string;
330
31
  style?: string | Record<string, any>;
331
- }` : "";
332
- const propsDefinition = typescript ? `
32
+ }`:""}${e?`
333
33
  const props = withDefaults(defineProps<Props>(), {
334
34
  class: '',
335
35
  style: undefined,
336
- });` : `
36
+ });`:`
337
37
  const props = withDefaults(defineProps(), {
338
38
  class: '',
339
39
  style: undefined,
340
- });`;
341
- return `<script setup${lang}>${propsType}${propsDefinition}
40
+ });`}
342
41
 
343
42
  // Component name for debugging
344
- const __name = '${componentName}';
345
- </script>`;
346
- }
347
- function generateCompositionScript(componentName, typescript) {
348
- const lang = typescript ? ' lang="ts"' : "";
349
- const propsType = typescript ? `
43
+ const __name = '${t}';
44
+ </script>`}function re(e,t){let r=t?' lang="ts"':"",n=t?`
350
45
  interface Props {
351
46
  class?: string;
352
47
  style?: string | Record<string, any>;
353
- }` : "";
354
- const exportStatement = typescript ? `
355
- const ${componentName} = defineComponent({
356
- name: '${componentName}',
48
+ }`:"",s=t?`
49
+ const ${e} = defineComponent({
50
+ name: '${e}',
357
51
  props: {
358
52
  class: {
359
53
  type: String,
@@ -369,10 +63,10 @@ const ${componentName} = defineComponent({
369
63
  },
370
64
  });
371
65
 
372
- export default ${componentName};
373
- export { ${componentName} };` : `
374
- const ${componentName} = defineComponent({
375
- name: '${componentName}',
66
+ export default ${e};
67
+ export { ${e} };`:`
68
+ const ${e} = defineComponent({
69
+ name: '${e}',
376
70
  props: {
377
71
  class: {
378
72
  type: String,
@@ -388,25 +82,20 @@ const ${componentName} = defineComponent({
388
82
  },
389
83
  });
390
84
 
391
- export default ${componentName};
392
- export { ${componentName} };`;
393
- return `<script${lang}>
394
- import { defineComponent } from 'vue';${propsType}${exportStatement}
395
- </script>`;
396
- }
397
- // Annotate the CommonJS export names for ESM import in node:
398
- 0 && (module.exports = {
399
- convertToReact,
400
- convertToVue,
401
- createSvgoConfig,
402
- formatComponentName,
403
- optimizeSvg,
404
- pascalCase,
405
- readSvgDirectory,
406
- readSvgFile,
407
- sanitizeComponentName,
408
- svgToComponentName,
409
- writeComponentFile,
410
- writeSvgFile
411
- });
412
- //# sourceMappingURL=index.js.map
85
+ export default ${e};
86
+ export { ${e} };`;return `<script${r}>
87
+ import { defineComponent } from 'vue';${n}${s}
88
+ </script>`}
89
+
90
+ exports.convertToReact = Y;
91
+ exports.convertToVue = ee;
92
+ exports.createSvgoConfig = B;
93
+ exports.formatComponentName = v;
94
+ exports.optimizeSvg = g;
95
+ exports.pascalCase = u;
96
+ exports.readSvgDirectory = T;
97
+ exports.readSvgFile = J;
98
+ exports.sanitizeComponentName = M;
99
+ exports.svgToComponentName = _;
100
+ exports.writeComponentFile = Q;
101
+ exports.writeSvgFile = K;
package/dist/index.mjs CHANGED
@@ -1,322 +1,51 @@
1
- // src/converters/react.ts
2
- import { transform } from "@svgr/core";
1
+ import { transform } from '@svgr/core';
2
+ import { optimize } from 'svgo';
3
+ import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';
4
+ import { dirname, join, extname } from 'path';
5
+ import { existsSync } from 'fs';
3
6
 
4
- // src/utils/svgo.ts
5
- import { optimize } from "svgo";
6
- var defaultConfig = {
7
- plugins: [
8
- {
9
- name: "preset-default",
10
- params: {
11
- overrides: {
12
- removeViewBox: false,
13
- removeTitle: false,
14
- removeDesc: false,
15
- removeUselessStrokeAndFill: false,
16
- convertColors: {
17
- currentColor: true,
18
- names2hex: true,
19
- rgb2hex: true,
20
- shorthex: true,
21
- // cspell:disable-line
22
- shortname: true
23
- }
24
- }
25
- }
26
- },
27
- "removeDimensions",
28
- "cleanupNumericValues"
29
- ]
30
- };
31
- function optimizeSvg(svgContent, config = defaultConfig) {
32
- try {
33
- const result = optimize(svgContent, config);
34
- return result.data;
35
- } catch (error) {
36
- throw new Error(`Failed to optimize SVG: ${error}`);
37
- }
38
- }
39
- function createSvgoConfig(options) {
40
- const plugins = [
41
- {
42
- name: "preset-default",
43
- params: {
44
- overrides: {
45
- removeViewBox: !options.removeViewBox,
46
- removeTitle: !options.removeTitle,
47
- removeDesc: !options.removeDesc,
48
- removeUselessStrokeAndFill: !options.preserveClasses,
49
- convertColors: options.preserveColors ? false : {
50
- currentColor: true,
51
- names2hex: true,
52
- rgb2hex: true,
53
- shorthex: true,
54
- // cspell:disable-line
55
- shortname: true
56
- }
57
- }
58
- }
59
- },
60
- "cleanupNumericValues"
61
- ];
62
- if (options.removeDimensions !== false) {
63
- plugins.push("removeDimensions");
64
- }
65
- return { plugins };
66
- }
67
-
68
- // src/utils/name.ts
69
- function svgToComponentName(filename) {
70
- let baseName = filename.replace(/\.svg$/i, "");
71
- baseName = processComplexFilename(baseName);
72
- return pascalCase(baseName);
73
- }
74
- function processComplexFilename(filename) {
75
- let processed = filename;
76
- const simpleMatch = processed.match(/^([^,]+),\s*Type=([^,]+)/i);
77
- if (simpleMatch) {
78
- processed = `${simpleMatch[1]} ${simpleMatch[2]}`;
79
- return processed;
80
- }
81
- const sizeMatch = processed.match(/Size=(\w+)/i);
82
- const colorMatch = processed.match(/Color=(\w+)/i);
83
- const typeMatch = processed.match(/Type=(\w+)/i);
84
- if (sizeMatch || colorMatch || typeMatch) {
85
- const parts = [];
86
- if (typeMatch)
87
- parts.push(typeMatch[1]);
88
- if (colorMatch)
89
- parts.push(colorMatch[1]);
90
- if (sizeMatch)
91
- parts.push(sizeMatch[1]);
92
- if (parts.length > 0) {
93
- processed = parts.join(" ");
94
- return processed;
95
- }
96
- }
97
- processed = processed.replace(/\b\w+=\w+\b/g, "").replace(/,\s*/g, " ").replace(/[=]/g, " ").replace(/\s+/g, " ").trim();
98
- if (!processed || processed.length < 2) {
99
- processed = filename;
100
- }
101
- return processed;
102
- }
103
- function sanitizeComponentName(name) {
104
- return pascalCase(name.replace(/[^a-zA-Z0-9]/g, " "));
105
- }
106
- function pascalCase(str) {
107
- return str.replace(/[^a-zA-Z0-9\s-_]/g, " ").split(/[\s-_]+/).filter((word) => word.length > 0).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
108
- }
109
- function formatComponentName(name, prefix, suffix) {
110
- const prefixPart = prefix ? pascalCase(prefix) : "";
111
- const suffixPart = suffix ? pascalCase(suffix) : "";
112
- const baseName = pascalCase(name);
113
- return `${prefixPart}${baseName}${suffixPart}`;
114
- }
115
-
116
- // src/utils/files.ts
117
- import { readFile, writeFile, readdir, stat, mkdir } from "fs/promises";
118
- import { join, dirname, extname } from "path";
119
- import { existsSync } from "fs";
120
- async function readSvgFile(filePath) {
121
- try {
122
- const content = await readFile(filePath, "utf-8");
123
- return content;
124
- } catch (error) {
125
- throw new Error(`Failed to read SVG file: ${filePath}. ${error}`);
126
- }
127
- }
128
- async function writeSvgFile(filePath, content) {
129
- try {
130
- await ensureDirectoryExists(dirname(filePath));
131
- await writeFile(filePath, content, "utf-8");
132
- } catch (error) {
133
- throw new Error(`Failed to write SVG file: ${filePath}. ${error}`);
134
- }
135
- }
136
- async function writeComponentFile(filePath, content) {
137
- try {
138
- await ensureDirectoryExists(dirname(filePath));
139
- await writeFile(filePath, content, "utf-8");
140
- } catch (error) {
141
- throw new Error(`Failed to write component file: ${filePath}. ${error}`);
142
- }
143
- }
144
- async function readSvgDirectory(dirPath, recursive = false) {
145
- try {
146
- const files = await readdir(dirPath);
147
- const svgFiles = [];
148
- for (const file of files) {
149
- const filePath = join(dirPath, file);
150
- const fileStat = await stat(filePath);
151
- if (fileStat.isDirectory() && recursive) {
152
- const nestedFiles = await readSvgDirectory(filePath, recursive);
153
- svgFiles.push(...nestedFiles);
154
- } else if (fileStat.isFile() && extname(file).toLowerCase() === ".svg") {
155
- svgFiles.push(filePath);
156
- }
157
- }
158
- return svgFiles;
159
- } catch (error) {
160
- throw new Error(`Failed to read directory: ${dirPath}. ${error}`);
161
- }
162
- }
163
- async function ensureDirectoryExists(dirPath) {
164
- if (!existsSync(dirPath)) {
165
- await mkdir(dirPath, { recursive: true });
166
- }
167
- }
168
- function getFileExtension(framework, typescript = true) {
169
- if (framework === "react") {
170
- return typescript ? ".tsx" : ".jsx";
171
- } else {
172
- return typescript ? ".vue" : ".vue";
173
- }
174
- }
175
- function getComponentFilename(_svgFilename, componentName, extension) {
176
- return `${componentName}${extension}`;
177
- }
7
+ var B={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:!1,removeTitle:!1,removeDesc:!1,removeUselessStrokeAndFill:!1,convertColors:{currentColor:!0,names2hex:!0,rgb2hex:!0,shorthex:!0,shortname:!0}}}},"removeDimensions","cleanupNumericValues"]};function v(e,t=B){try{return optimize(e,t).data}catch(r){throw new Error(`Failed to optimize SVG: ${r}`)}}function _(e){let t=[{name:"preset-default",params:{overrides:{removeViewBox:!e.removeViewBox,removeTitle:!e.removeTitle,removeDesc:!e.removeDesc,removeUselessStrokeAndFill:!e.preserveClasses,convertColors:e.preserveColors?!1:{currentColor:!0,names2hex:!0,rgb2hex:!0,shorthex:!0,shortname:!0}}}},"cleanupNumericValues"];return e.removeDimensions!==!1&&t.push("removeDimensions"),{plugins:t}}function k(e){let t=e.replace(/\.svg$/i,"");return t=M(t),u(t)}function M(e){let t=e,r=t.match(/^([^,]+),\s*Type=([^,]+)/i);if(r)return t=`${r[1]} ${r[2]}`,t;let n=t.match(/Size=(\w+)/i),s=t.match(/Color=(\w+)/i),i=t.match(/Type=(\w+)/i);if(n||s||i){let o=[];if(i&&o.push(i[1]),s&&o.push(s[1]),n&&o.push(n[1]),o.length>0)return t=o.join(" "),t}return t=t.replace(/\b\w+=\w+\b/g,"").replace(/,\s*/g," ").replace(/[=]/g," ").replace(/\s+/g," ").trim(),(!t||t.length<2)&&(t=e),t}function I(e){return u(e.replace(/[^a-zA-Z0-9]/g," "))}function u(e){return e.replace(/[^a-zA-Z0-9\s-_]/g," ").split(/[\s-_]+/).filter(t=>t.length>0).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function d(e,t,r){let n=t?u(t):"",s=r?u(r):"",i=u(e);return `${n}${i}${s}`}async function K(e){try{return await readFile(e,"utf-8")}catch(t){throw new Error(`Failed to read SVG file: ${e}. ${t}`)}}async function Q(e,t){try{await N(dirname(e)),await writeFile(e,t,"utf-8");}catch(r){throw new Error(`Failed to write SVG file: ${e}. ${r}`)}}async function X(e,t){try{await N(dirname(e)),await writeFile(e,t,"utf-8");}catch(r){throw new Error(`Failed to write component file: ${e}. ${r}`)}}async function D(e,t=!1){try{let r=await readdir(e),n=[];for(let s of r){let i=join(e,s),o=await stat(i);if(o.isDirectory()&&t){let c=await D(i,t);n.push(...c);}else o.isFile()&&extname(s).toLowerCase()===".svg"&&n.push(i);}return n}catch(r){throw new Error(`Failed to read directory: ${e}. ${r}`)}}async function N(e){existsSync(e)||await mkdir(e,{recursive:!0});}function $(e,t=!0){return e==="react"?t?".tsx":".jsx":".vue"}function x(e,t,r){return `${t}${r}`}async function ee(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,memo:c=!0,ref:l=!0,titleProp:m=!0,descProp:S=!0}=t;try{let p=e;i&&(p=v(e));let a=d(r||"icon",n,s),C=await transform(p,{typescript:o,memo:c,ref:l,titleProp:m,descProp:S,svgProps:{className:"{className}"}},{componentName:a}),w=o?`import { SVGProps } from 'react';
8
+ `:"",y=c?`import { memo } from 'react';
9
+ `:"",h=l?`import { forwardRef } from 'react';
10
+ `:"",z=`
11
+ export default ${a};
12
+ export { ${a} };`,V=o?"SVGProps<SVGSVGElement> & { className?: string; }":"",E=o?`props: ${V}`:"props",O=c?"memo(":"",P=l?`forwardRef<SVGSVGElement, ${V}>(`:"";C=`${w}${y}${h}
13
+ const ${a} = ${O}${P}(${E}) => {
14
+ return ${C};
15
+ }${`${l?")":""}${c?")":""}`};
178
16
 
179
- // src/converters/react.ts
180
- async function convertToReact(svgContent, options = {}) {
181
- const {
182
- name,
183
- prefix,
184
- suffix,
185
- optimize: optimize2 = true,
186
- typescript = true,
187
- memo = true,
188
- ref = true,
189
- titleProp = true,
190
- descProp = true
191
- } = options;
192
- try {
193
- let processedSvg = svgContent;
194
- if (optimize2) {
195
- processedSvg = optimizeSvg(svgContent);
196
- }
197
- const baseName = name || "icon";
198
- const componentName = formatComponentName(baseName, prefix, suffix);
199
- const svgrOptions = {
200
- typescript,
201
- memo,
202
- ref,
203
- titleProp,
204
- descProp,
205
- svgProps: {
206
- className: "{className}"
207
- }
208
- };
209
- let result = await transform(processedSvg, svgrOptions, {
210
- componentName
211
- });
212
- const typeImports = typescript ? `import { SVGProps } from 'react';
213
- ` : "";
214
- const memoImport = memo ? `import { memo } from 'react';
215
- ` : "";
216
- const refImport = ref ? `import { forwardRef } from 'react';
217
- ` : "";
218
- const exports = `
219
- export default ${componentName};
220
- export { ${componentName} };`;
221
- const propsType = typescript ? `SVGProps<SVGSVGElement> & { className?: string; }` : "";
222
- const componentProps = typescript ? `props: ${propsType}` : "props";
223
- const componentFunc = memo ? `memo(` : "";
224
- const refWrapper = ref ? `forwardRef<SVGSVGElement, ${propsType}>(` : "";
225
- const closingWrappers = `${ref ? ")" : ""}${memo ? ")" : ""}`;
226
- result = `${typeImports}${memoImport}${refImport}
227
- const ${componentName} = ${componentFunc}${refWrapper}(${componentProps}) => {
228
- return ${result};
229
- }${closingWrappers};
17
+ ${a}.displayName = "${a}";
18
+ ${z}`;let G=$("react",o),A=x("icon.svg",a,G);return {code:C,filename:A,componentName:a}}catch(p){throw new Error(`Failed to convert SVG to React: ${p}`)}}function te(e,t={}){let{name:r,prefix:n,suffix:s,optimize:i=!0,typescript:o=!0,compositionApi:c=!0,scriptSetup:l=!0}=t;try{let m=e;i&&(m=v(e));let p=d(r||"icon",n,s),F=m.replace(/<\?xml[^>]*\?>\s*/,"").replace(/xmlns="[^"]*"/g,"").replace(/width="[^"]*"/g,"").replace(/height="[^"]*"/g,"").replace(/<svg/,'<svg v-bind="$attrs"').replace(/class="([^"]*)"/g,'class="$1"').replace(/currentColor/g,"currentColor"),a=l?re(o,p):oe(p,o),b=`<template>
19
+ ${F}
20
+ </template>`,w=`${a}
230
21
 
231
- ${componentName}.displayName = "${componentName}";
232
- ${exports}`;
233
- const extension = getFileExtension("react", typescript);
234
- const filename = getComponentFilename("icon.svg", componentName, extension);
235
- return {
236
- code: result,
237
- filename,
238
- componentName
239
- };
240
- } catch (error) {
241
- throw new Error(`Failed to convert SVG to React: ${error}`);
242
- }
243
- }
22
+ ${b}
244
23
 
245
- // src/converters/vue.ts
246
- function convertToVue(svgContent, options = {}) {
247
- const {
248
- name,
249
- prefix,
250
- suffix,
251
- optimize: optimize2 = true,
252
- typescript = true,
253
- compositionApi: _compositionApi = true,
254
- // eslint-disable-line @typescript-eslint/no-unused-vars
255
- scriptSetup = true
256
- } = options;
257
- try {
258
- let processedSvg = svgContent;
259
- if (optimize2) {
260
- processedSvg = optimizeSvg(svgContent);
261
- }
262
- const baseName = name || "icon";
263
- const componentName = formatComponentName(baseName, prefix, suffix);
264
- const cleanedSvg = processedSvg.replace(/<\?xml[^>]*\?>\s*/, "").replace(/xmlns="[^"]*"/g, "").replace(/width="[^"]*"/g, "").replace(/height="[^"]*"/g, "").replace(/<svg/, '<svg v-bind="$attrs"').replace(/class="([^"]*)"/g, 'class="$1"').replace(/currentColor/g, "currentColor");
265
- const scriptTag = scriptSetup ? generateScriptSetup(typescript, componentName) : generateCompositionScript(componentName, typescript);
266
- const template = `<template>
267
- ${cleanedSvg}
268
- </template>`;
269
- const style = `<style scoped>
24
+ <style scoped>
270
25
  /* Add component-specific styles here */
271
- </style>`;
272
- const vueComponent = `${scriptTag}
273
-
274
- ${template}
275
-
276
- ${style}`;
277
- const extension = getFileExtension("vue", typescript);
278
- const filename = getComponentFilename("icon.svg", componentName, extension);
279
- return {
280
- code: vueComponent,
281
- filename,
282
- componentName
283
- };
284
- } catch (error) {
285
- throw new Error(`Failed to convert SVG to Vue: ${error}`);
286
- }
287
- }
288
- function generateScriptSetup(typescript, componentName) {
289
- const lang = typescript ? ' lang="ts"' : "";
290
- const propsType = typescript ? `
26
+ </style>`,y=$("vue",o),h=x("icon.svg",p,y);return {code:w,filename:h,componentName:p}}catch(m){throw new Error(`Failed to convert SVG to Vue: ${m}`)}}function re(e,t){return `<script setup${e?' lang="ts"':""}>${e?`
291
27
  interface Props {
292
28
  class?: string;
293
29
  style?: string | Record<string, any>;
294
- }` : "";
295
- const propsDefinition = typescript ? `
30
+ }`:""}${e?`
296
31
  const props = withDefaults(defineProps<Props>(), {
297
32
  class: '',
298
33
  style: undefined,
299
- });` : `
34
+ });`:`
300
35
  const props = withDefaults(defineProps(), {
301
36
  class: '',
302
37
  style: undefined,
303
- });`;
304
- return `<script setup${lang}>${propsType}${propsDefinition}
38
+ });`}
305
39
 
306
40
  // Component name for debugging
307
- const __name = '${componentName}';
308
- </script>`;
309
- }
310
- function generateCompositionScript(componentName, typescript) {
311
- const lang = typescript ? ' lang="ts"' : "";
312
- const propsType = typescript ? `
41
+ const __name = '${t}';
42
+ </script>`}function oe(e,t){let r=t?' lang="ts"':"",n=t?`
313
43
  interface Props {
314
44
  class?: string;
315
45
  style?: string | Record<string, any>;
316
- }` : "";
317
- const exportStatement = typescript ? `
318
- const ${componentName} = defineComponent({
319
- name: '${componentName}',
46
+ }`:"",s=t?`
47
+ const ${e} = defineComponent({
48
+ name: '${e}',
320
49
  props: {
321
50
  class: {
322
51
  type: String,
@@ -332,10 +61,10 @@ const ${componentName} = defineComponent({
332
61
  },
333
62
  });
334
63
 
335
- export default ${componentName};
336
- export { ${componentName} };` : `
337
- const ${componentName} = defineComponent({
338
- name: '${componentName}',
64
+ export default ${e};
65
+ export { ${e} };`:`
66
+ const ${e} = defineComponent({
67
+ name: '${e}',
339
68
  props: {
340
69
  class: {
341
70
  type: String,
@@ -351,24 +80,9 @@ const ${componentName} = defineComponent({
351
80
  },
352
81
  });
353
82
 
354
- export default ${componentName};
355
- export { ${componentName} };`;
356
- return `<script${lang}>
357
- import { defineComponent } from 'vue';${propsType}${exportStatement}
358
- </script>`;
359
- }
360
- export {
361
- convertToReact,
362
- convertToVue,
363
- createSvgoConfig,
364
- formatComponentName,
365
- optimizeSvg,
366
- pascalCase,
367
- readSvgDirectory,
368
- readSvgFile,
369
- sanitizeComponentName,
370
- svgToComponentName,
371
- writeComponentFile,
372
- writeSvgFile
373
- };
374
- //# sourceMappingURL=index.mjs.map
83
+ export default ${e};
84
+ export { ${e} };`;return `<script${r}>
85
+ import { defineComponent } from 'vue';${n}${s}
86
+ </script>`}
87
+
88
+ export { ee as convertToReact, te as convertToVue, _ as createSvgoConfig, d as formatComponentName, v as optimizeSvg, u as pascalCase, D as readSvgDirectory, K as readSvgFile, I as sanitizeComponentName, k as svgToComponentName, X as writeComponentFile, Q as writeSvgFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svgfusion",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.3",
4
4
  "description": "Transform SVG files into production-ready React and Vue 3 components with TypeScript support, automatic optimization, and intelligent naming.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/cli.mjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/converters/react.ts","../src/utils/svgo.ts","../src/utils/name.ts","../src/utils/files.ts","../src/converters/vue.ts"],"sourcesContent":["export type {\n ConversionOptions,\n ReactConversionOptions,\n VueConversionOptions,\n ConversionResult,\n BatchConversionOptions,\n BatchConversionResult,\n ConversionError,\n Framework,\n CliOptions,\n} from './types/index.js';\n\nexport { convertToReact } from './converters/react.js';\nexport { convertToVue } from './converters/vue.js';\nexport { optimizeSvg, createSvgoConfig } from './utils/svgo.js';\nexport {\n readSvgFile,\n writeSvgFile,\n readSvgDirectory,\n writeComponentFile,\n} from './utils/files.js';\nexport {\n svgToComponentName,\n sanitizeComponentName,\n pascalCase,\n formatComponentName,\n} from './utils/name.js';\n","import { transform } from '@svgr/core';\nimport { ReactConversionOptions, ConversionResult } from '../types/index.js';\nimport { optimizeSvg } from '../utils/svgo.js';\nimport { formatComponentName } from '../utils/name.js';\nimport { getFileExtension, getComponentFilename } from '../utils/files.js';\n\n/**\n * Convert SVG to React component\n * @param svgContent - SVG content string\n * @param options - Conversion options\n * @returns Conversion result with React component code\n */\nexport async function convertToReact(\n svgContent: string,\n options: ReactConversionOptions = {}\n): Promise<ConversionResult> {\n const {\n name,\n prefix,\n suffix,\n optimize = true,\n typescript = true,\n memo = true,\n ref = true,\n titleProp = true,\n descProp = true,\n } = options;\n\n try {\n // Optimize SVG if requested\n let processedSvg = svgContent;\n if (optimize) {\n processedSvg = optimizeSvg(svgContent);\n }\n\n // Generate component name\n const baseName = name || 'icon';\n const componentName = formatComponentName(baseName, prefix, suffix);\n\n // SVGR transformation options\n const svgrOptions = {\n typescript,\n memo,\n ref,\n titleProp,\n descProp,\n svgProps: {\n className: '{className}',\n },\n };\n\n // Transform SVG to React component\n let result = await transform(processedSvg, svgrOptions, {\n componentName,\n });\n\n // Add proper exports to the result\n const typeImports = typescript ? `import { SVGProps } from 'react';\\n` : '';\n\n const memoImport = memo ? `import { memo } from 'react';\\n` : '';\n const refImport = ref ? `import { forwardRef } from 'react';\\n` : '';\n\n const exports = `\\nexport default ${componentName};\\nexport { ${componentName} };`;\n\n // Wrap the SVGR result with proper component structure\n const propsType = typescript\n ? `SVGProps<SVGSVGElement> & { className?: string; }`\n : '';\n\n const componentProps = typescript ? `props: ${propsType}` : 'props';\n\n const componentFunc = memo ? `memo(` : '';\n const refWrapper = ref ? `forwardRef<SVGSVGElement, ${propsType}>(` : '';\n const closingWrappers = `${ref ? ')' : ''}${memo ? ')' : ''}`;\n\n result = `${typeImports}${memoImport}${refImport}\nconst ${componentName} = ${componentFunc}${refWrapper}(${componentProps}) => {\n return ${result};\n}${closingWrappers};\n\n${componentName}.displayName = \"${componentName}\";\n${exports}`;\n\n // Generate filename\n const extension = getFileExtension('react', typescript);\n const filename = getComponentFilename('icon.svg', componentName, extension);\n\n return {\n code: result,\n filename,\n componentName,\n };\n } catch (error) {\n throw new Error(`Failed to convert SVG to React: ${error}`);\n }\n}\n","import { optimize, Config } from 'svgo';\n\n/**\n * Default SVGO configuration for optimization\n */\nconst defaultConfig: Config = {\n plugins: [\n {\n name: 'preset-default',\n params: {\n overrides: {\n removeViewBox: false,\n removeTitle: false,\n removeDesc: false,\n removeUselessStrokeAndFill: false,\n convertColors: {\n currentColor: true,\n names2hex: true,\n rgb2hex: true,\n shorthex: true, // cspell:disable-line\n shortname: true,\n },\n },\n },\n },\n 'removeDimensions',\n 'cleanupNumericValues',\n ],\n};\n\n/**\n * Optimize SVG content using SVGO\n * @param svgContent - SVG content to optimize\n * @param config - Optional SVGO configuration\n * @returns Optimized SVG content\n */\nexport function optimizeSvg(\n svgContent: string,\n config: Config = defaultConfig\n): string {\n try {\n const result = optimize(svgContent, config);\n return result.data;\n } catch (error) {\n throw new Error(`Failed to optimize SVG: ${error}`);\n }\n}\n\n/**\n * Create custom SVGO configuration\n * @param options - Configuration options\n * @returns SVGO configuration\n */\nexport function createSvgoConfig(options: {\n removeViewBox?: boolean;\n removeDimensions?: boolean;\n removeTitle?: boolean;\n removeDesc?: boolean;\n preserveAspectRatio?: boolean;\n preserveColors?: boolean;\n preserveClasses?: boolean;\n}): Config {\n const plugins = [\n {\n name: 'preset-default',\n params: {\n overrides: {\n removeViewBox: !options.removeViewBox,\n removeTitle: !options.removeTitle,\n removeDesc: !options.removeDesc,\n removeUselessStrokeAndFill: !options.preserveClasses,\n convertColors: options.preserveColors\n ? false\n : {\n currentColor: true,\n names2hex: true,\n rgb2hex: true,\n shorthex: true, // cspell:disable-line\n shortname: true,\n },\n },\n },\n },\n 'cleanupNumericValues',\n ];\n\n if (options.removeDimensions !== false) {\n plugins.push('removeDimensions');\n }\n\n return { plugins: plugins as Config['plugins'] };\n}\n","/**\n * Convert SVG filename to a valid React component name\n * @param filename - The SVG filename\n * @returns PascalCase component name\n */\nexport function svgToComponentName(filename: string): string {\n // Remove file extension\n let baseName = filename.replace(/\\.svg$/i, '');\n\n // Handle complex filenames with metadata\n baseName = processComplexFilename(baseName);\n\n // Convert to PascalCase\n return pascalCase(baseName);\n}\n\n/**\n * Process complex filenames with metadata and special characters\n * @param filename - The filename to process\n * @returns Cleaned filename\n */\nfunction processComplexFilename(filename: string): string {\n // Handle files with metadata like \"User Profile Avatar, Type=Solid\" or \"Size=xl, Color=Brand, Type=Glass\"\n\n let processed = filename;\n\n // Handle simple patterns like \"User Profile Avatar, Type=Solid\" first\n const simpleMatch = processed.match(/^([^,]+),\\s*Type=([^,]+)/i);\n if (simpleMatch) {\n processed = `${simpleMatch[1]} ${simpleMatch[2]}`;\n return processed;\n }\n\n // Check for metadata patterns\n const sizeMatch = processed.match(/Size=(\\w+)/i);\n const colorMatch = processed.match(/Color=(\\w+)/i);\n const typeMatch = processed.match(/Type=(\\w+)/i);\n\n // If it has metadata, construct a meaningful name\n if (sizeMatch || colorMatch || typeMatch) {\n const parts = [];\n if (typeMatch) parts.push(typeMatch[1]);\n if (colorMatch) parts.push(colorMatch[1]);\n if (sizeMatch) parts.push(sizeMatch[1]);\n\n if (parts.length > 0) {\n processed = parts.join(' ');\n return processed;\n }\n }\n\n // If no metadata patterns found, just clean up the filename\n processed = processed\n .replace(/\\b\\w+=\\w+\\b/g, '') // Remove key=value patterns\n .replace(/,\\s*/g, ' ') // Replace commas with spaces\n .replace(/[=]/g, ' ') // Replace equals with spaces\n .replace(/\\s+/g, ' ') // Normalize multiple spaces\n .trim();\n\n // If the result is empty or too short, use original filename as fallback\n if (!processed || processed.length < 2) {\n processed = filename;\n }\n\n return processed;\n}\n\n/**\n * Sanitize component name to ensure it's valid\n * @param name - The component name to sanitize\n * @returns Sanitized component name\n */\nexport function sanitizeComponentName(name: string): string {\n // Remove invalid characters and convert to PascalCase\n return pascalCase(name.replace(/[^a-zA-Z0-9]/g, ' '));\n}\n\n/**\n * Convert a string to PascalCase\n * @param str - The string to convert\n * @returns PascalCase string\n */\nexport function pascalCase(str: string): string {\n return str\n .replace(/[^a-zA-Z0-9\\s-_]/g, ' ') // Remove any symbols, keep spaces, hyphens, underscores\n .split(/[\\s-_]+/) // Split on spaces, hyphens, underscores\n .filter(word => word.length > 0) // Remove empty strings\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Add prefix/suffix to component name\n * @param name - Base component name\n * @param prefix - Optional prefix\n * @param suffix - Optional suffix\n * @returns Component name with prefix/suffix\n */\nexport function formatComponentName(\n name: string,\n prefix?: string,\n suffix?: string\n): string {\n const prefixPart = prefix ? pascalCase(prefix) : '';\n const suffixPart = suffix ? pascalCase(suffix) : '';\n const baseName = pascalCase(name);\n\n return `${prefixPart}${baseName}${suffixPart}`;\n}\n","import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';\nimport { join, dirname, extname } from 'path';\nimport { existsSync } from 'fs';\n\n/**\n * Read SVG file content\n * @param filePath - Path to the SVG file\n * @returns SVG content as string\n */\nexport async function readSvgFile(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf-8');\n return content;\n } catch (error) {\n throw new Error(`Failed to read SVG file: ${filePath}. ${error}`);\n }\n}\n\n/**\n * Write SVG file content\n * @param filePath - Path to write the SVG file\n * @param content - SVG content\n */\nexport async function writeSvgFile(\n filePath: string,\n content: string\n): Promise<void> {\n try {\n await ensureDirectoryExists(dirname(filePath));\n await writeFile(filePath, content, 'utf-8');\n } catch (error) {\n throw new Error(`Failed to write SVG file: ${filePath}. ${error}`);\n }\n}\n\n/**\n * Write component file content\n * @param filePath - Path to write the component file\n * @param content - Component content\n */\nexport async function writeComponentFile(\n filePath: string,\n content: string\n): Promise<void> {\n try {\n await ensureDirectoryExists(dirname(filePath));\n await writeFile(filePath, content, 'utf-8');\n } catch (error) {\n throw new Error(`Failed to write component file: ${filePath}. ${error}`);\n }\n}\n\n/**\n * Read all SVG files from a directory\n * @param dirPath - Directory path\n * @param recursive - Whether to read recursively\n * @returns Array of SVG file paths\n */\nexport async function readSvgDirectory(\n dirPath: string,\n recursive = false\n): Promise<string[]> {\n try {\n const files = await readdir(dirPath);\n const svgFiles: string[] = [];\n\n for (const file of files) {\n const filePath = join(dirPath, file);\n const fileStat = await stat(filePath);\n\n if (fileStat.isDirectory() && recursive) {\n const nestedFiles = await readSvgDirectory(filePath, recursive);\n svgFiles.push(...nestedFiles);\n } else if (fileStat.isFile() && extname(file).toLowerCase() === '.svg') {\n svgFiles.push(filePath);\n }\n }\n\n return svgFiles;\n } catch (error) {\n throw new Error(`Failed to read directory: ${dirPath}. ${error}`);\n }\n}\n\n/**\n * Ensure directory exists, create if not\n * @param dirPath - Directory path\n */\nexport async function ensureDirectoryExists(dirPath: string): Promise<void> {\n if (!existsSync(dirPath)) {\n await mkdir(dirPath, { recursive: true });\n }\n}\n\n/**\n * Get file extension for framework\n * @param framework - Target framework\n * @param typescript - Whether to use TypeScript\n * @returns File extension\n */\nexport function getFileExtension(\n framework: 'react' | 'vue',\n typescript = true\n): string {\n if (framework === 'react') {\n return typescript ? '.tsx' : '.jsx';\n } else {\n return typescript ? '.vue' : '.vue';\n }\n}\n\n/**\n * Get component filename from SVG filename\n * @param svgFilename - SVG filename\n * @param componentName - Component name\n * @param extension - File extension\n * @returns Component filename\n */\nexport function getComponentFilename(\n _svgFilename: string,\n componentName: string,\n extension: string\n): string {\n return `${componentName}${extension}`;\n}\n","import { VueConversionOptions, ConversionResult } from '../types/index.js';\nimport { optimizeSvg } from '../utils/svgo.js';\nimport { formatComponentName } from '../utils/name.js';\nimport { getFileExtension, getComponentFilename } from '../utils/files.js';\n\n/**\n * Convert SVG to Vue 3 component\n * @param svgContent - SVG content string\n * @param options - Conversion options\n * @returns Conversion result with Vue component code\n */\nexport function convertToVue(\n svgContent: string,\n options: VueConversionOptions = {}\n): ConversionResult {\n const {\n name,\n prefix,\n suffix,\n optimize = true,\n typescript = true,\n compositionApi: _compositionApi = true, // eslint-disable-line @typescript-eslint/no-unused-vars\n scriptSetup = true,\n } = options;\n\n try {\n // Optimize SVG if requested\n let processedSvg = svgContent;\n if (optimize) {\n processedSvg = optimizeSvg(svgContent);\n }\n\n // Generate component name\n const baseName = name || 'icon';\n const componentName = formatComponentName(baseName, prefix, suffix);\n\n // Clean up SVG - remove XML declaration and add props binding\n const cleanedSvg = processedSvg\n .replace(/<\\?xml[^>]*\\?>\\s*/, '')\n .replace(/xmlns=\"[^\"]*\"/g, '')\n .replace(/width=\"[^\"]*\"/g, '')\n .replace(/height=\"[^\"]*\"/g, '')\n .replace(/<svg/, '<svg v-bind=\"$attrs\"')\n .replace(/class=\"([^\"]*)\"/g, 'class=\"$1\"') // Keep class as is, don't convert to :class\n .replace(/currentColor/g, 'currentColor');\n\n // Generate Vue SFC\n const scriptTag = scriptSetup\n ? generateScriptSetup(typescript, componentName)\n : generateCompositionScript(componentName, typescript);\n\n const template = `<template>\n ${cleanedSvg}\n</template>`;\n\n const style = `<style scoped>\n/* Add component-specific styles here */\n</style>`;\n\n const vueComponent = `${scriptTag}\n\n${template}\n\n${style}`;\n\n // Generate filename\n const extension = getFileExtension('vue', typescript);\n const filename = getComponentFilename('icon.svg', componentName, extension);\n\n return {\n code: vueComponent,\n filename,\n componentName,\n };\n } catch (error) {\n throw new Error(`Failed to convert SVG to Vue: ${error}`);\n }\n}\n\n/**\n * Generate script setup block for Vue 3\n */\nfunction generateScriptSetup(\n typescript: boolean,\n componentName: string\n): string {\n const lang = typescript ? ' lang=\"ts\"' : '';\n const propsType = typescript\n ? `\ninterface Props {\n class?: string;\n style?: string | Record<string, any>;\n}`\n : '';\n\n const propsDefinition = typescript\n ? `\nconst props = withDefaults(defineProps<Props>(), {\n class: '',\n style: undefined,\n});`\n : `\nconst props = withDefaults(defineProps(), {\n class: '',\n style: undefined,\n});`;\n\n return `<script setup${lang}>${propsType}${propsDefinition}\n\n// Component name for debugging\nconst __name = '${componentName}';\n</script>`;\n}\n\n/**\n * Generate composition API script for Vue 3\n */\nfunction generateCompositionScript(\n componentName: string,\n typescript: boolean\n): string {\n const lang = typescript ? ' lang=\"ts\"' : '';\n const propsType = typescript\n ? `\ninterface Props {\n class?: string;\n style?: string | Record<string, any>;\n}`\n : '';\n\n const exportStatement = typescript\n ? `\nconst ${componentName} = defineComponent({\n name: '${componentName}',\n props: {\n class: {\n type: String,\n default: '',\n },\n style: {\n type: [String, Object],\n default: undefined,\n },\n },\n setup(props: Props) {\n return {};\n },\n});\n\nexport default ${componentName};\nexport { ${componentName} };`\n : `\nconst ${componentName} = defineComponent({\n name: '${componentName}',\n props: {\n class: {\n type: String,\n default: '',\n },\n style: {\n type: [String, Object],\n default: undefined,\n },\n },\n setup(props) {\n return {};\n },\n});\n\nexport default ${componentName};\nexport { ${componentName} };`;\n\n return `<script${lang}>\nimport { defineComponent } from 'vue';${propsType}${exportStatement}\n</script>`;\n}\n"],"mappings":"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","names":["optimize","optimize"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/converters/react.ts","../src/utils/svgo.ts","../src/utils/name.ts","../src/utils/files.ts","../src/converters/vue.ts"],"sourcesContent":["import { transform } from '@svgr/core';\nimport { ReactConversionOptions, ConversionResult } from '../types/index.js';\nimport { optimizeSvg } from '../utils/svgo.js';\nimport { formatComponentName } from '../utils/name.js';\nimport { getFileExtension, getComponentFilename } from '../utils/files.js';\n\n/**\n * Convert SVG to React component\n * @param svgContent - SVG content string\n * @param options - Conversion options\n * @returns Conversion result with React component code\n */\nexport async function convertToReact(\n svgContent: string,\n options: ReactConversionOptions = {}\n): Promise<ConversionResult> {\n const {\n name,\n prefix,\n suffix,\n optimize = true,\n typescript = true,\n memo = true,\n ref = true,\n titleProp = true,\n descProp = true,\n } = options;\n\n try {\n // Optimize SVG if requested\n let processedSvg = svgContent;\n if (optimize) {\n processedSvg = optimizeSvg(svgContent);\n }\n\n // Generate component name\n const baseName = name || 'icon';\n const componentName = formatComponentName(baseName, prefix, suffix);\n\n // SVGR transformation options\n const svgrOptions = {\n typescript,\n memo,\n ref,\n titleProp,\n descProp,\n svgProps: {\n className: '{className}',\n },\n };\n\n // Transform SVG to React component\n let result = await transform(processedSvg, svgrOptions, {\n componentName,\n });\n\n // Add proper exports to the result\n const typeImports = typescript ? `import { SVGProps } from 'react';\\n` : '';\n\n const memoImport = memo ? `import { memo } from 'react';\\n` : '';\n const refImport = ref ? `import { forwardRef } from 'react';\\n` : '';\n\n const exports = `\\nexport default ${componentName};\\nexport { ${componentName} };`;\n\n // Wrap the SVGR result with proper component structure\n const propsType = typescript\n ? `SVGProps<SVGSVGElement> & { className?: string; }`\n : '';\n\n const componentProps = typescript ? `props: ${propsType}` : 'props';\n\n const componentFunc = memo ? `memo(` : '';\n const refWrapper = ref ? `forwardRef<SVGSVGElement, ${propsType}>(` : '';\n const closingWrappers = `${ref ? ')' : ''}${memo ? ')' : ''}`;\n\n result = `${typeImports}${memoImport}${refImport}\nconst ${componentName} = ${componentFunc}${refWrapper}(${componentProps}) => {\n return ${result};\n}${closingWrappers};\n\n${componentName}.displayName = \"${componentName}\";\n${exports}`;\n\n // Generate filename\n const extension = getFileExtension('react', typescript);\n const filename = getComponentFilename('icon.svg', componentName, extension);\n\n return {\n code: result,\n filename,\n componentName,\n };\n } catch (error) {\n throw new Error(`Failed to convert SVG to React: ${error}`);\n }\n}\n","import { optimize, Config } from 'svgo';\n\n/**\n * Default SVGO configuration for optimization\n */\nconst defaultConfig: Config = {\n plugins: [\n {\n name: 'preset-default',\n params: {\n overrides: {\n removeViewBox: false,\n removeTitle: false,\n removeDesc: false,\n removeUselessStrokeAndFill: false,\n convertColors: {\n currentColor: true,\n names2hex: true,\n rgb2hex: true,\n shorthex: true, // cspell:disable-line\n shortname: true,\n },\n },\n },\n },\n 'removeDimensions',\n 'cleanupNumericValues',\n ],\n};\n\n/**\n * Optimize SVG content using SVGO\n * @param svgContent - SVG content to optimize\n * @param config - Optional SVGO configuration\n * @returns Optimized SVG content\n */\nexport function optimizeSvg(\n svgContent: string,\n config: Config = defaultConfig\n): string {\n try {\n const result = optimize(svgContent, config);\n return result.data;\n } catch (error) {\n throw new Error(`Failed to optimize SVG: ${error}`);\n }\n}\n\n/**\n * Create custom SVGO configuration\n * @param options - Configuration options\n * @returns SVGO configuration\n */\nexport function createSvgoConfig(options: {\n removeViewBox?: boolean;\n removeDimensions?: boolean;\n removeTitle?: boolean;\n removeDesc?: boolean;\n preserveAspectRatio?: boolean;\n preserveColors?: boolean;\n preserveClasses?: boolean;\n}): Config {\n const plugins = [\n {\n name: 'preset-default',\n params: {\n overrides: {\n removeViewBox: !options.removeViewBox,\n removeTitle: !options.removeTitle,\n removeDesc: !options.removeDesc,\n removeUselessStrokeAndFill: !options.preserveClasses,\n convertColors: options.preserveColors\n ? false\n : {\n currentColor: true,\n names2hex: true,\n rgb2hex: true,\n shorthex: true, // cspell:disable-line\n shortname: true,\n },\n },\n },\n },\n 'cleanupNumericValues',\n ];\n\n if (options.removeDimensions !== false) {\n plugins.push('removeDimensions');\n }\n\n return { plugins: plugins as Config['plugins'] };\n}\n","/**\n * Convert SVG filename to a valid React component name\n * @param filename - The SVG filename\n * @returns PascalCase component name\n */\nexport function svgToComponentName(filename: string): string {\n // Remove file extension\n let baseName = filename.replace(/\\.svg$/i, '');\n\n // Handle complex filenames with metadata\n baseName = processComplexFilename(baseName);\n\n // Convert to PascalCase\n return pascalCase(baseName);\n}\n\n/**\n * Process complex filenames with metadata and special characters\n * @param filename - The filename to process\n * @returns Cleaned filename\n */\nfunction processComplexFilename(filename: string): string {\n // Handle files with metadata like \"User Profile Avatar, Type=Solid\" or \"Size=xl, Color=Brand, Type=Glass\"\n\n let processed = filename;\n\n // Handle simple patterns like \"User Profile Avatar, Type=Solid\" first\n const simpleMatch = processed.match(/^([^,]+),\\s*Type=([^,]+)/i);\n if (simpleMatch) {\n processed = `${simpleMatch[1]} ${simpleMatch[2]}`;\n return processed;\n }\n\n // Check for metadata patterns\n const sizeMatch = processed.match(/Size=(\\w+)/i);\n const colorMatch = processed.match(/Color=(\\w+)/i);\n const typeMatch = processed.match(/Type=(\\w+)/i);\n\n // If it has metadata, construct a meaningful name\n if (sizeMatch || colorMatch || typeMatch) {\n const parts = [];\n if (typeMatch) parts.push(typeMatch[1]);\n if (colorMatch) parts.push(colorMatch[1]);\n if (sizeMatch) parts.push(sizeMatch[1]);\n\n if (parts.length > 0) {\n processed = parts.join(' ');\n return processed;\n }\n }\n\n // If no metadata patterns found, just clean up the filename\n processed = processed\n .replace(/\\b\\w+=\\w+\\b/g, '') // Remove key=value patterns\n .replace(/,\\s*/g, ' ') // Replace commas with spaces\n .replace(/[=]/g, ' ') // Replace equals with spaces\n .replace(/\\s+/g, ' ') // Normalize multiple spaces\n .trim();\n\n // If the result is empty or too short, use original filename as fallback\n if (!processed || processed.length < 2) {\n processed = filename;\n }\n\n return processed;\n}\n\n/**\n * Sanitize component name to ensure it's valid\n * @param name - The component name to sanitize\n * @returns Sanitized component name\n */\nexport function sanitizeComponentName(name: string): string {\n // Remove invalid characters and convert to PascalCase\n return pascalCase(name.replace(/[^a-zA-Z0-9]/g, ' '));\n}\n\n/**\n * Convert a string to PascalCase\n * @param str - The string to convert\n * @returns PascalCase string\n */\nexport function pascalCase(str: string): string {\n return str\n .replace(/[^a-zA-Z0-9\\s-_]/g, ' ') // Remove any symbols, keep spaces, hyphens, underscores\n .split(/[\\s-_]+/) // Split on spaces, hyphens, underscores\n .filter(word => word.length > 0) // Remove empty strings\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Add prefix/suffix to component name\n * @param name - Base component name\n * @param prefix - Optional prefix\n * @param suffix - Optional suffix\n * @returns Component name with prefix/suffix\n */\nexport function formatComponentName(\n name: string,\n prefix?: string,\n suffix?: string\n): string {\n const prefixPart = prefix ? pascalCase(prefix) : '';\n const suffixPart = suffix ? pascalCase(suffix) : '';\n const baseName = pascalCase(name);\n\n return `${prefixPart}${baseName}${suffixPart}`;\n}\n","import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';\nimport { join, dirname, extname } from 'path';\nimport { existsSync } from 'fs';\n\n/**\n * Read SVG file content\n * @param filePath - Path to the SVG file\n * @returns SVG content as string\n */\nexport async function readSvgFile(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf-8');\n return content;\n } catch (error) {\n throw new Error(`Failed to read SVG file: ${filePath}. ${error}`);\n }\n}\n\n/**\n * Write SVG file content\n * @param filePath - Path to write the SVG file\n * @param content - SVG content\n */\nexport async function writeSvgFile(\n filePath: string,\n content: string\n): Promise<void> {\n try {\n await ensureDirectoryExists(dirname(filePath));\n await writeFile(filePath, content, 'utf-8');\n } catch (error) {\n throw new Error(`Failed to write SVG file: ${filePath}. ${error}`);\n }\n}\n\n/**\n * Write component file content\n * @param filePath - Path to write the component file\n * @param content - Component content\n */\nexport async function writeComponentFile(\n filePath: string,\n content: string\n): Promise<void> {\n try {\n await ensureDirectoryExists(dirname(filePath));\n await writeFile(filePath, content, 'utf-8');\n } catch (error) {\n throw new Error(`Failed to write component file: ${filePath}. ${error}`);\n }\n}\n\n/**\n * Read all SVG files from a directory\n * @param dirPath - Directory path\n * @param recursive - Whether to read recursively\n * @returns Array of SVG file paths\n */\nexport async function readSvgDirectory(\n dirPath: string,\n recursive = false\n): Promise<string[]> {\n try {\n const files = await readdir(dirPath);\n const svgFiles: string[] = [];\n\n for (const file of files) {\n const filePath = join(dirPath, file);\n const fileStat = await stat(filePath);\n\n if (fileStat.isDirectory() && recursive) {\n const nestedFiles = await readSvgDirectory(filePath, recursive);\n svgFiles.push(...nestedFiles);\n } else if (fileStat.isFile() && extname(file).toLowerCase() === '.svg') {\n svgFiles.push(filePath);\n }\n }\n\n return svgFiles;\n } catch (error) {\n throw new Error(`Failed to read directory: ${dirPath}. ${error}`);\n }\n}\n\n/**\n * Ensure directory exists, create if not\n * @param dirPath - Directory path\n */\nexport async function ensureDirectoryExists(dirPath: string): Promise<void> {\n if (!existsSync(dirPath)) {\n await mkdir(dirPath, { recursive: true });\n }\n}\n\n/**\n * Get file extension for framework\n * @param framework - Target framework\n * @param typescript - Whether to use TypeScript\n * @returns File extension\n */\nexport function getFileExtension(\n framework: 'react' | 'vue',\n typescript = true\n): string {\n if (framework === 'react') {\n return typescript ? '.tsx' : '.jsx';\n } else {\n return typescript ? '.vue' : '.vue';\n }\n}\n\n/**\n * Get component filename from SVG filename\n * @param svgFilename - SVG filename\n * @param componentName - Component name\n * @param extension - File extension\n * @returns Component filename\n */\nexport function getComponentFilename(\n _svgFilename: string,\n componentName: string,\n extension: string\n): string {\n return `${componentName}${extension}`;\n}\n","import { VueConversionOptions, ConversionResult } from '../types/index.js';\nimport { optimizeSvg } from '../utils/svgo.js';\nimport { formatComponentName } from '../utils/name.js';\nimport { getFileExtension, getComponentFilename } from '../utils/files.js';\n\n/**\n * Convert SVG to Vue 3 component\n * @param svgContent - SVG content string\n * @param options - Conversion options\n * @returns Conversion result with Vue component code\n */\nexport function convertToVue(\n svgContent: string,\n options: VueConversionOptions = {}\n): ConversionResult {\n const {\n name,\n prefix,\n suffix,\n optimize = true,\n typescript = true,\n compositionApi: _compositionApi = true, // eslint-disable-line @typescript-eslint/no-unused-vars\n scriptSetup = true,\n } = options;\n\n try {\n // Optimize SVG if requested\n let processedSvg = svgContent;\n if (optimize) {\n processedSvg = optimizeSvg(svgContent);\n }\n\n // Generate component name\n const baseName = name || 'icon';\n const componentName = formatComponentName(baseName, prefix, suffix);\n\n // Clean up SVG - remove XML declaration and add props binding\n const cleanedSvg = processedSvg\n .replace(/<\\?xml[^>]*\\?>\\s*/, '')\n .replace(/xmlns=\"[^\"]*\"/g, '')\n .replace(/width=\"[^\"]*\"/g, '')\n .replace(/height=\"[^\"]*\"/g, '')\n .replace(/<svg/, '<svg v-bind=\"$attrs\"')\n .replace(/class=\"([^\"]*)\"/g, 'class=\"$1\"') // Keep class as is, don't convert to :class\n .replace(/currentColor/g, 'currentColor');\n\n // Generate Vue SFC\n const scriptTag = scriptSetup\n ? generateScriptSetup(typescript, componentName)\n : generateCompositionScript(componentName, typescript);\n\n const template = `<template>\n ${cleanedSvg}\n</template>`;\n\n const style = `<style scoped>\n/* Add component-specific styles here */\n</style>`;\n\n const vueComponent = `${scriptTag}\n\n${template}\n\n${style}`;\n\n // Generate filename\n const extension = getFileExtension('vue', typescript);\n const filename = getComponentFilename('icon.svg', componentName, extension);\n\n return {\n code: vueComponent,\n filename,\n componentName,\n };\n } catch (error) {\n throw new Error(`Failed to convert SVG to Vue: ${error}`);\n }\n}\n\n/**\n * Generate script setup block for Vue 3\n */\nfunction generateScriptSetup(\n typescript: boolean,\n componentName: string\n): string {\n const lang = typescript ? ' lang=\"ts\"' : '';\n const propsType = typescript\n ? `\ninterface Props {\n class?: string;\n style?: string | Record<string, any>;\n}`\n : '';\n\n const propsDefinition = typescript\n ? `\nconst props = withDefaults(defineProps<Props>(), {\n class: '',\n style: undefined,\n});`\n : `\nconst props = withDefaults(defineProps(), {\n class: '',\n style: undefined,\n});`;\n\n return `<script setup${lang}>${propsType}${propsDefinition}\n\n// Component name for debugging\nconst __name = '${componentName}';\n</script>`;\n}\n\n/**\n * Generate composition API script for Vue 3\n */\nfunction generateCompositionScript(\n componentName: string,\n typescript: boolean\n): string {\n const lang = typescript ? ' lang=\"ts\"' : '';\n const propsType = typescript\n ? `\ninterface Props {\n class?: string;\n style?: string | Record<string, any>;\n}`\n : '';\n\n const exportStatement = typescript\n ? `\nconst ${componentName} = defineComponent({\n name: '${componentName}',\n props: {\n class: {\n type: String,\n default: '',\n },\n style: {\n type: [String, Object],\n default: undefined,\n },\n },\n setup(props: Props) {\n return {};\n },\n});\n\nexport default ${componentName};\nexport { ${componentName} };`\n : `\nconst ${componentName} = defineComponent({\n name: '${componentName}',\n props: {\n class: {\n type: String,\n default: '',\n },\n style: {\n type: [String, Object],\n default: undefined,\n },\n },\n setup(props) {\n return {};\n },\n});\n\nexport default ${componentName};\nexport { ${componentName} };`;\n\n return `<script${lang}>\nimport { defineComponent } from 'vue';${propsType}${exportStatement}\n</script>`;\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;;;ACA1B,SAAS,gBAAwB;AAKjC,IAAM,gBAAwB;AAAA,EAC5B,SAAS;AAAA,IACP;AAAA,MACE,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,WAAW;AAAA,UACT,eAAe;AAAA,UACf,aAAa;AAAA,UACb,YAAY;AAAA,UACZ,4BAA4B;AAAA,UAC5B,eAAe;AAAA,YACb,cAAc;AAAA,YACd,WAAW;AAAA,YACX,SAAS;AAAA,YACT,UAAU;AAAA;AAAA,YACV,WAAW;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAQO,SAAS,YACd,YACA,SAAiB,eACT;AACR,MAAI;AACF,UAAM,SAAS,SAAS,YAAY,MAAM;AAC1C,WAAO,OAAO;AAAA,EAChB,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,2BAA2B,KAAK,EAAE;AAAA,EACpD;AACF;AAOO,SAAS,iBAAiB,SAQtB;AACT,QAAM,UAAU;AAAA,IACd;AAAA,MACE,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,WAAW;AAAA,UACT,eAAe,CAAC,QAAQ;AAAA,UACxB,aAAa,CAAC,QAAQ;AAAA,UACtB,YAAY,CAAC,QAAQ;AAAA,UACrB,4BAA4B,CAAC,QAAQ;AAAA,UACrC,eAAe,QAAQ,iBACnB,QACA;AAAA,YACE,cAAc;AAAA,YACd,WAAW;AAAA,YACX,SAAS;AAAA,YACT,UAAU;AAAA;AAAA,YACV,WAAW;AAAA,UACb;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAEA,MAAI,QAAQ,qBAAqB,OAAO;AACtC,YAAQ,KAAK,kBAAkB;AAAA,EACjC;AAEA,SAAO,EAAE,QAAsC;AACjD;;;ACtFO,SAAS,mBAAmB,UAA0B;AAE3D,MAAI,WAAW,SAAS,QAAQ,WAAW,EAAE;AAG7C,aAAW,uBAAuB,QAAQ;AAG1C,SAAO,WAAW,QAAQ;AAC5B;AAOA,SAAS,uBAAuB,UAA0B;AAGxD,MAAI,YAAY;AAGhB,QAAM,cAAc,UAAU,MAAM,2BAA2B;AAC/D,MAAI,aAAa;AACf,gBAAY,GAAG,YAAY,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC;AAC/C,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,UAAU,MAAM,aAAa;AAC/C,QAAM,aAAa,UAAU,MAAM,cAAc;AACjD,QAAM,YAAY,UAAU,MAAM,aAAa;AAG/C,MAAI,aAAa,cAAc,WAAW;AACxC,UAAM,QAAQ,CAAC;AACf,QAAI;AAAW,YAAM,KAAK,UAAU,CAAC,CAAC;AACtC,QAAI;AAAY,YAAM,KAAK,WAAW,CAAC,CAAC;AACxC,QAAI;AAAW,YAAM,KAAK,UAAU,CAAC,CAAC;AAEtC,QAAI,MAAM,SAAS,GAAG;AACpB,kBAAY,MAAM,KAAK,GAAG;AAC1B,aAAO;AAAA,IACT;AAAA,EACF;AAGA,cAAY,UACT,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,SAAS,GAAG,EACpB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AAGR,MAAI,CAAC,aAAa,UAAU,SAAS,GAAG;AACtC,gBAAY;AAAA,EACd;AAEA,SAAO;AACT;AAOO,SAAS,sBAAsB,MAAsB;AAE1D,SAAO,WAAW,KAAK,QAAQ,iBAAiB,GAAG,CAAC;AACtD;AAOO,SAAS,WAAW,KAAqB;AAC9C,SAAO,IACJ,QAAQ,qBAAqB,GAAG,EAChC,MAAM,SAAS,EACf,OAAO,UAAQ,KAAK,SAAS,CAAC,EAC9B,IAAI,UAAQ,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY,CAAC,EACtE,KAAK,EAAE;AACZ;AASO,SAAS,oBACd,MACA,QACA,QACQ;AACR,QAAM,aAAa,SAAS,WAAW,MAAM,IAAI;AACjD,QAAM,aAAa,SAAS,WAAW,MAAM,IAAI;AACjD,QAAM,WAAW,WAAW,IAAI;AAEhC,SAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU;AAC9C;;;AC5GA,SAAS,UAAU,WAAW,SAAS,MAAM,aAAa;AAC1D,SAAS,MAAM,SAAS,eAAe;AACvC,SAAS,kBAAkB;AAO3B,eAAsB,YAAY,UAAmC;AACnE,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,4BAA4B,QAAQ,KAAK,KAAK,EAAE;AAAA,EAClE;AACF;AAOA,eAAsB,aACpB,UACA,SACe;AACf,MAAI;AACF,UAAM,sBAAsB,QAAQ,QAAQ,CAAC;AAC7C,UAAM,UAAU,UAAU,SAAS,OAAO;AAAA,EAC5C,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,6BAA6B,QAAQ,KAAK,KAAK,EAAE;AAAA,EACnE;AACF;AAOA,eAAsB,mBACpB,UACA,SACe;AACf,MAAI;AACF,UAAM,sBAAsB,QAAQ,QAAQ,CAAC;AAC7C,UAAM,UAAU,UAAU,SAAS,OAAO;AAAA,EAC5C,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,mCAAmC,QAAQ,KAAK,KAAK,EAAE;AAAA,EACzE;AACF;AAQA,eAAsB,iBACpB,SACA,YAAY,OACO;AACnB,MAAI;AACF,UAAM,QAAQ,MAAM,QAAQ,OAAO;AACnC,UAAM,WAAqB,CAAC;AAE5B,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,KAAK,SAAS,IAAI;AACnC,YAAM,WAAW,MAAM,KAAK,QAAQ;AAEpC,UAAI,SAAS,YAAY,KAAK,WAAW;AACvC,cAAM,cAAc,MAAM,iBAAiB,UAAU,SAAS;AAC9D,iBAAS,KAAK,GAAG,WAAW;AAAA,MAC9B,WAAW,SAAS,OAAO,KAAK,QAAQ,IAAI,EAAE,YAAY,MAAM,QAAQ;AACtE,iBAAS,KAAK,QAAQ;AAAA,MACxB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,6BAA6B,OAAO,KAAK,KAAK,EAAE;AAAA,EAClE;AACF;AAMA,eAAsB,sBAAsB,SAAgC;AAC1E,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,UAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AACF;AAQO,SAAS,iBACd,WACA,aAAa,MACL;AACR,MAAI,cAAc,SAAS;AACzB,WAAO,aAAa,SAAS;AAAA,EAC/B,OAAO;AACL,WAAO,aAAa,SAAS;AAAA,EAC/B;AACF;AASO,SAAS,qBACd,cACA,eACA,WACQ;AACR,SAAO,GAAG,aAAa,GAAG,SAAS;AACrC;;;AHhHA,eAAsB,eACpB,YACA,UAAkC,CAAC,GACR;AAC3B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAAA,YAAW;AAAA,IACX,aAAa;AAAA,IACb,OAAO;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EACb,IAAI;AAEJ,MAAI;AAEF,QAAI,eAAe;AACnB,QAAIA,WAAU;AACZ,qBAAe,YAAY,UAAU;AAAA,IACvC;AAGA,UAAM,WAAW,QAAQ;AACzB,UAAM,gBAAgB,oBAAoB,UAAU,QAAQ,MAAM;AAGlE,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,QACR,WAAW;AAAA,MACb;AAAA,IACF;AAGA,QAAI,SAAS,MAAM,UAAU,cAAc,aAAa;AAAA,MACtD;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,aAAa;AAAA,IAAwC;AAEzE,UAAM,aAAa,OAAO;AAAA,IAAoC;AAC9D,UAAM,YAAY,MAAM;AAAA,IAA0C;AAElE,UAAM,UAAU;AAAA,iBAAoB,aAAa;AAAA,WAAe,aAAa;AAG7E,UAAM,YAAY,aACd,sDACA;AAEJ,UAAM,iBAAiB,aAAa,UAAU,SAAS,KAAK;AAE5D,UAAM,gBAAgB,OAAO,UAAU;AACvC,UAAM,aAAa,MAAM,6BAA6B,SAAS,OAAO;AACtE,UAAM,kBAAkB,GAAG,MAAM,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE;AAE3D,aAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS;AAAA,QAC5C,aAAa,MAAM,aAAa,GAAG,UAAU,IAAI,cAAc;AAAA,WAC5D,MAAM;AAAA,GACd,eAAe;AAAA;AAAA,EAEhB,aAAa,mBAAmB,aAAa;AAAA,EAC7C,OAAO;AAGL,UAAM,YAAY,iBAAiB,SAAS,UAAU;AACtD,UAAM,WAAW,qBAAqB,YAAY,eAAe,SAAS;AAE1E,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,mCAAmC,KAAK,EAAE;AAAA,EAC5D;AACF;;;AIpFO,SAAS,aACd,YACA,UAAgC,CAAC,GACf;AAClB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAAC,YAAW;AAAA,IACX,aAAa;AAAA,IACb,gBAAgB,kBAAkB;AAAA;AAAA,IAClC,cAAc;AAAA,EAChB,IAAI;AAEJ,MAAI;AAEF,QAAI,eAAe;AACnB,QAAIA,WAAU;AACZ,qBAAe,YAAY,UAAU;AAAA,IACvC;AAGA,UAAM,WAAW,QAAQ;AACzB,UAAM,gBAAgB,oBAAoB,UAAU,QAAQ,MAAM;AAGlE,UAAM,aAAa,aAChB,QAAQ,qBAAqB,EAAE,EAC/B,QAAQ,kBAAkB,EAAE,EAC5B,QAAQ,kBAAkB,EAAE,EAC5B,QAAQ,mBAAmB,EAAE,EAC7B,QAAQ,QAAQ,sBAAsB,EACtC,QAAQ,oBAAoB,YAAY,EACxC,QAAQ,iBAAiB,cAAc;AAG1C,UAAM,YAAY,cACd,oBAAoB,YAAY,aAAa,IAC7C,0BAA0B,eAAe,UAAU;AAEvD,UAAM,WAAW;AAAA,IACjB,UAAU;AAAA;AAGV,UAAM,QAAQ;AAAA;AAAA;AAId,UAAM,eAAe,GAAG,SAAS;AAAA;AAAA,EAEnC,QAAQ;AAAA;AAAA,EAER,KAAK;AAGH,UAAM,YAAY,iBAAiB,OAAO,UAAU;AACpD,UAAM,WAAW,qBAAqB,YAAY,eAAe,SAAS;AAE1E,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,iCAAiC,KAAK,EAAE;AAAA,EAC1D;AACF;AAKA,SAAS,oBACP,YACA,eACQ;AACR,QAAM,OAAO,aAAa,eAAe;AACzC,QAAM,YAAY,aACd;AAAA;AAAA;AAAA;AAAA,KAKA;AAEJ,QAAM,kBAAkB,aACpB;AAAA;AAAA;AAAA;AAAA,OAKA;AAAA;AAAA;AAAA;AAAA;AAMJ,SAAO,gBAAgB,IAAI,IAAI,SAAS,GAAG,eAAe;AAAA;AAAA;AAAA,kBAG1C,aAAa;AAAA;AAE/B;AAKA,SAAS,0BACP,eACA,YACQ;AACR,QAAM,OAAO,aAAa,eAAe;AACzC,QAAM,YAAY,aACd;AAAA;AAAA;AAAA;AAAA,KAKA;AAEJ,QAAM,kBAAkB,aACpB;AAAA,QACE,aAAa;AAAA,WACV,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAgBP,aAAa;AAAA,WACnB,aAAa,QAClB;AAAA,QACE,aAAa;AAAA,WACV,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAgBP,aAAa;AAAA,WACnB,aAAa;AAEtB,SAAO,UAAU,IAAI;AAAA,wCACiB,SAAS,GAAG,eAAe;AAAA;AAEnE;","names":["optimize","optimize"]}