vectify 2.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +679 -0
  3. package/README.zh-CN.md +683 -0
  4. package/dist/chunk-4BWKFV7W.mjs +1311 -0
  5. package/dist/chunk-CIKTK6HI.mjs +96 -0
  6. package/dist/cli.d.mts +1 -0
  7. package/dist/cli.d.ts +1 -0
  8. package/dist/cli.js +1483 -0
  9. package/dist/cli.mjs +56 -0
  10. package/dist/helpers-UPZEBRGK.mjs +26 -0
  11. package/dist/index.d.mts +281 -0
  12. package/dist/index.d.ts +281 -0
  13. package/dist/index.js +1463 -0
  14. package/dist/index.mjs +27 -0
  15. package/dist/templates/angular/component.ts.hbs +121 -0
  16. package/dist/templates/angular/createIcon.ts.hbs +116 -0
  17. package/dist/templates/astro/component.astro.hbs +110 -0
  18. package/dist/templates/astro/createIcon.astro.hbs +111 -0
  19. package/dist/templates/lit/component.js.hbs +12 -0
  20. package/dist/templates/lit/component.ts.hbs +19 -0
  21. package/dist/templates/lit/createIcon.js.hbs +98 -0
  22. package/dist/templates/lit/createIcon.ts.hbs +99 -0
  23. package/dist/templates/preact/component.jsx.hbs +8 -0
  24. package/dist/templates/preact/component.tsx.hbs +11 -0
  25. package/dist/templates/preact/createIcon.jsx.hbs +101 -0
  26. package/dist/templates/preact/createIcon.tsx.hbs +121 -0
  27. package/dist/templates/qwik/component.jsx.hbs +7 -0
  28. package/dist/templates/qwik/component.tsx.hbs +8 -0
  29. package/dist/templates/qwik/createIcon.jsx.hbs +100 -0
  30. package/dist/templates/qwik/createIcon.tsx.hbs +111 -0
  31. package/dist/templates/react/component.jsx.hbs +8 -0
  32. package/dist/templates/react/component.tsx.hbs +11 -0
  33. package/dist/templates/react/createIcon.jsx.hbs +100 -0
  34. package/dist/templates/react/createIcon.tsx.hbs +117 -0
  35. package/dist/templates/solid/component.tsx.hbs +10 -0
  36. package/dist/templates/solid/createIcon.jsx.hbs +127 -0
  37. package/dist/templates/solid/createIcon.tsx.hbs +139 -0
  38. package/dist/templates/svelte/component.js.svelte.hbs +9 -0
  39. package/dist/templates/svelte/component.ts.svelte.hbs +10 -0
  40. package/dist/templates/svelte/icon.js.svelte.hbs +123 -0
  41. package/dist/templates/svelte/icon.ts.svelte.hbs +124 -0
  42. package/dist/templates/template-engine.ts +107 -0
  43. package/dist/templates/vanilla/component.ts.hbs +8 -0
  44. package/dist/templates/vanilla/createIcon.js.hbs +111 -0
  45. package/dist/templates/vanilla/createIcon.ts.hbs +124 -0
  46. package/dist/templates/vue/component.js.vue.hbs +21 -0
  47. package/dist/templates/vue/component.ts.vue.hbs +22 -0
  48. package/dist/templates/vue/icon.js.vue.hbs +155 -0
  49. package/dist/templates/vue/icon.ts.vue.hbs +157 -0
  50. package/package.json +78 -0
package/dist/index.js ADDED
@@ -0,0 +1,1463 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/utils/helpers.ts
34
+ var helpers_exports = {};
35
+ __export(helpers_exports, {
36
+ ensureDir: () => ensureDir,
37
+ fileExists: () => fileExists,
38
+ findProjectRoot: () => findProjectRoot,
39
+ formatAttributes: () => formatAttributes,
40
+ getComponentName: () => getComponentName,
41
+ getSvgFiles: () => getSvgFiles,
42
+ mergeClasses: () => mergeClasses,
43
+ readFile: () => readFile,
44
+ toKebabCase: () => toKebabCase,
45
+ toPascalCase: () => toPascalCase,
46
+ writeFile: () => writeFile
47
+ });
48
+ function toPascalCase(str) {
49
+ return str.replace(/[-_](.)/g, (_, char) => char.toUpperCase()).replace(/^(.)/, (char) => char.toUpperCase()).replace(/[^a-z0-9]/gi, "");
50
+ }
51
+ function toKebabCase(str) {
52
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
53
+ }
54
+ function mergeClasses(...classes) {
55
+ return classes.filter(Boolean).join(" ");
56
+ }
57
+ function getComponentName(fileName, prefix = "", suffix = "", transform) {
58
+ const baseName = fileName.replace(/\.svg$/, "");
59
+ let componentName = toPascalCase(baseName);
60
+ if (transform) {
61
+ componentName = transform(componentName);
62
+ }
63
+ return `${prefix}${componentName}${suffix}`;
64
+ }
65
+ function formatAttributes(attrs) {
66
+ const entries = Object.entries(attrs);
67
+ if (entries.length === 0)
68
+ return "{}";
69
+ const formatted = entries.map(([key, value]) => {
70
+ if (typeof value === "number") {
71
+ return `${key}: ${value}`;
72
+ }
73
+ return `${key}: '${value}'`;
74
+ }).join(", ");
75
+ return `{ ${formatted} }`;
76
+ }
77
+ async function ensureDir(dirPath) {
78
+ const fs2 = await import("fs/promises");
79
+ try {
80
+ await fs2.mkdir(dirPath, { recursive: true });
81
+ } catch (error) {
82
+ if (error.code !== "EEXIST") {
83
+ throw error;
84
+ }
85
+ }
86
+ }
87
+ async function fileExists(filePath) {
88
+ const fs2 = await import("fs/promises");
89
+ try {
90
+ await fs2.access(filePath);
91
+ return true;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
96
+ async function readFile(filePath) {
97
+ const fs2 = await import("fs/promises");
98
+ return await fs2.readFile(filePath, "utf-8");
99
+ }
100
+ async function writeFile(filePath, content) {
101
+ const fs2 = await import("fs/promises");
102
+ await fs2.writeFile(filePath, content, "utf-8");
103
+ }
104
+ async function getSvgFiles(dirPath) {
105
+ const fs2 = await import("fs/promises");
106
+ const path6 = await import("path");
107
+ try {
108
+ const files = await fs2.readdir(dirPath);
109
+ return files.filter((file) => file.endsWith(".svg")).map((file) => path6.join(dirPath, file));
110
+ } catch {
111
+ return [];
112
+ }
113
+ }
114
+ async function findProjectRoot(startDir = process.cwd()) {
115
+ const path6 = await import("path");
116
+ let currentDir = startDir;
117
+ while (true) {
118
+ const packageJsonPath = path6.join(currentDir, "package.json");
119
+ if (await fileExists(packageJsonPath)) {
120
+ return currentDir;
121
+ }
122
+ const parentDir = path6.dirname(currentDir);
123
+ if (parentDir === currentDir) {
124
+ return startDir;
125
+ }
126
+ currentDir = parentDir;
127
+ }
128
+ }
129
+ var init_helpers = __esm({
130
+ "src/utils/helpers.ts"() {
131
+ "use strict";
132
+ }
133
+ });
134
+
135
+ // src/index.ts
136
+ var src_exports = {};
137
+ __export(src_exports, {
138
+ defineConfig: () => defineConfig,
139
+ findConfig: () => findConfig,
140
+ frameworkRegistry: () => frameworkRegistry,
141
+ generate: () => generate,
142
+ generateIcons: () => generateIcons,
143
+ getFrameworkStrategy: () => getFrameworkStrategy,
144
+ init: () => init,
145
+ loadConfig: () => loadConfig,
146
+ watch: () => watch
147
+ });
148
+ module.exports = __toCommonJS(src_exports);
149
+
150
+ // src/commands/generate.ts
151
+ var import_chalk = __toESM(require("chalk"));
152
+ var import_ora = __toESM(require("ora"));
153
+
154
+ // src/config/loader.ts
155
+ var import_node_path2 = __toESM(require("path"));
156
+ var import_node_process = __toESM(require("process"));
157
+ var import_jiti = require("jiti");
158
+
159
+ // src/parsers/svg-parser.ts
160
+ var cheerio = __toESM(require("cheerio"));
161
+ var SUPPORTED_ELEMENTS = [
162
+ "circle",
163
+ "ellipse",
164
+ "line",
165
+ "path",
166
+ "polygon",
167
+ "polyline",
168
+ "rect",
169
+ "g"
170
+ ];
171
+ function parseSvg(svgContent) {
172
+ const $ = cheerio.load(svgContent, {
173
+ xml: true
174
+ });
175
+ const svgElement = $("svg");
176
+ if (svgElement.length === 0) {
177
+ throw new Error("Invalid SVG: No <svg> tag found");
178
+ }
179
+ const iconNodes = [];
180
+ svgElement.children().each((_, element) => {
181
+ const node = parseElement($, element);
182
+ if (node) {
183
+ iconNodes.push(node);
184
+ }
185
+ });
186
+ return iconNodes;
187
+ }
188
+ function parseElement($, element) {
189
+ if (element.type !== "tag") {
190
+ return null;
191
+ }
192
+ const tagName = element.name;
193
+ if (!SUPPORTED_ELEMENTS.includes(tagName)) {
194
+ return null;
195
+ }
196
+ const attrs = parseAttributes(element);
197
+ const $element = $(element);
198
+ const children = [];
199
+ $element.children().each((_, child) => {
200
+ const childNode = parseElement($, child);
201
+ if (childNode) {
202
+ children.push(childNode);
203
+ }
204
+ });
205
+ if (children.length > 0) {
206
+ return [tagName, attrs, children];
207
+ }
208
+ return [tagName, attrs];
209
+ }
210
+ function parseAttributes(element) {
211
+ const attrs = {};
212
+ if (element.type !== "tag" || !element.attribs) {
213
+ return attrs;
214
+ }
215
+ const attributes = element.attribs;
216
+ for (const [key, value] of Object.entries(attributes)) {
217
+ if (key.startsWith("xmlns")) {
218
+ continue;
219
+ }
220
+ if (typeof value !== "string") {
221
+ continue;
222
+ }
223
+ const camelKey = key.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
224
+ const numValue = Number.parseFloat(value);
225
+ attrs[camelKey] = Number.isNaN(numValue) ? value : numValue;
226
+ }
227
+ return attrs;
228
+ }
229
+ function formatIconNode(node, indent = 2) {
230
+ const [elementType, attrs, children] = node;
231
+ const indentStr = " ".repeat(indent);
232
+ const attrsStr = formatAttrs(attrs);
233
+ if (children && children.length > 0) {
234
+ const childrenStr = children.map((child) => formatIconNode(child, indent + 2)).join(",\n");
235
+ return `${indentStr}['${elementType}', ${attrsStr}, [
236
+ ${childrenStr}
237
+ ${indentStr}]]`;
238
+ }
239
+ return `${indentStr}['${elementType}', ${attrsStr}]`;
240
+ }
241
+ function formatAttrs(attrs) {
242
+ const entries = Object.entries(attrs);
243
+ if (entries.length === 0) {
244
+ return "{}";
245
+ }
246
+ const formatted = entries.map(([key, value]) => {
247
+ if (typeof value === "number") {
248
+ return `${key}: ${value}`;
249
+ }
250
+ const escaped = value.replace(/'/g, "\\'");
251
+ return `${key}: '${escaped}'`;
252
+ }).join(", ");
253
+ return `{ ${formatted} }`;
254
+ }
255
+
256
+ // src/generators/templates/template-engine.ts
257
+ var import_node_fs = __toESM(require("fs"));
258
+ var import_node_path = __toESM(require("path"));
259
+ var import_node_url = require("url");
260
+ var import_handlebars = __toESM(require("handlebars"));
261
+ var import_meta = {};
262
+ function getTemplatesDir() {
263
+ if (typeof __dirname !== "undefined") {
264
+ return import_node_path.default.join(__dirname, "templates");
265
+ }
266
+ const currentFile = (0, import_node_url.fileURLToPath)(import_meta.url);
267
+ return import_node_path.default.join(import_node_path.default.dirname(currentFile), "templates");
268
+ }
269
+ function loadTemplate(templatePath) {
270
+ const templatesDir = getTemplatesDir();
271
+ const fullPath = import_node_path.default.join(templatesDir, templatePath);
272
+ const templateContent = import_node_fs.default.readFileSync(fullPath, "utf-8");
273
+ return import_handlebars.default.compile(templateContent, { noEscape: true });
274
+ }
275
+ function renderTemplate(templatePath, data) {
276
+ const template = loadTemplate(templatePath);
277
+ return template(data);
278
+ }
279
+ function getReactTemplatePath(typescript, type) {
280
+ const ext = typescript ? "tsx" : "jsx";
281
+ return `react/${type}.${ext}.hbs`;
282
+ }
283
+ function getVueTemplatePath(typescript, type) {
284
+ const suffix = typescript ? "ts" : "js";
285
+ return `vue/${type}.${suffix}.vue.hbs`;
286
+ }
287
+ function getSvelteTemplatePath(typescript, type) {
288
+ const suffix = typescript ? "ts" : "js";
289
+ return `svelte/${type}.${suffix}.svelte.hbs`;
290
+ }
291
+ function getSolidTemplatePath(typescript, type) {
292
+ const ext = typescript ? "tsx" : "jsx";
293
+ return `solid/${type}.${ext}.hbs`;
294
+ }
295
+ function getPreactTemplatePath(typescript, type) {
296
+ const ext = typescript ? "tsx" : "jsx";
297
+ return `preact/${type}.${ext}.hbs`;
298
+ }
299
+ function getVanillaTemplatePath(typescript, type) {
300
+ const ext = typescript ? "ts" : "js";
301
+ return `vanilla/${type}.${ext}.hbs`;
302
+ }
303
+ function getQwikTemplatePath(typescript, type) {
304
+ const ext = typescript ? "tsx" : "jsx";
305
+ return `qwik/${type}.${ext}.hbs`;
306
+ }
307
+
308
+ // src/generators/angular.ts
309
+ function getAngularTemplatePath(type) {
310
+ return `angular/${type}.ts.hbs`;
311
+ }
312
+ function generateAngularComponent(componentName, iconNode, typescript, keepColors = false) {
313
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
314
+ const templatePath = getAngularTemplatePath("component");
315
+ return renderTemplate(templatePath, {
316
+ componentName,
317
+ formattedNodes,
318
+ typescript,
319
+ keepColors
320
+ });
321
+ }
322
+ function generateAngularBaseComponent(typescript) {
323
+ const templatePath = getAngularTemplatePath("createIcon");
324
+ return {
325
+ code: renderTemplate(templatePath, { typescript }),
326
+ fileName: "createIcon.ts"
327
+ };
328
+ }
329
+
330
+ // src/generators/astro.ts
331
+ function getAstroTemplatePath(type) {
332
+ return `astro/${type}.astro.hbs`;
333
+ }
334
+ function generateAstroComponent(componentName, iconNode, typescript, keepColors = false) {
335
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
336
+ const templatePath = getAstroTemplatePath("component");
337
+ return renderTemplate(templatePath, {
338
+ componentName,
339
+ formattedNodes,
340
+ typescript,
341
+ keepColors
342
+ });
343
+ }
344
+ function generateAstroBaseComponent(typescript) {
345
+ const templatePath = getAstroTemplatePath("createIcon");
346
+ return {
347
+ code: renderTemplate(templatePath, { typescript }),
348
+ fileName: "createIcon.astro"
349
+ };
350
+ }
351
+
352
+ // src/generators/lit.ts
353
+ function getLitTemplatePath(typescript, type) {
354
+ const ext = typescript ? "ts" : "js";
355
+ return `lit/${type}.${ext}.hbs`;
356
+ }
357
+ function generateLitComponent(componentName, iconNode, typescript, keepColors = false) {
358
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
359
+ const templatePath = getLitTemplatePath(typescript, "component");
360
+ return renderTemplate(templatePath, {
361
+ componentName,
362
+ formattedNodes,
363
+ typescript,
364
+ keepColors
365
+ });
366
+ }
367
+ function generateLitBaseComponent(typescript) {
368
+ const templatePath = getLitTemplatePath(typescript, "createIcon");
369
+ return {
370
+ code: renderTemplate(templatePath, { typescript }),
371
+ fileName: typescript ? "createIcon.ts" : "createIcon.js"
372
+ };
373
+ }
374
+
375
+ // src/generators/react.ts
376
+ function generateReactComponent(componentName, iconNode, typescript, keepColors = false) {
377
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
378
+ const templatePath = getReactTemplatePath(typescript, "component");
379
+ return renderTemplate(templatePath, {
380
+ typescript,
381
+ componentName,
382
+ formattedNodes,
383
+ keepColors
384
+ });
385
+ }
386
+ function generateCreateIcon(typescript) {
387
+ const templatePath = getReactTemplatePath(typescript, "createIcon");
388
+ return renderTemplate(templatePath, { typescript });
389
+ }
390
+
391
+ // src/generators/react-like.ts
392
+ function generateReactLikeComponent(componentName, iconNode, typescript, keepColors, framework) {
393
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
394
+ let templatePath;
395
+ if (framework === "solid") {
396
+ templatePath = getSolidTemplatePath(typescript, "component");
397
+ } else if (framework === "preact") {
398
+ templatePath = getPreactTemplatePath(typescript, "component");
399
+ } else if (framework === "qwik") {
400
+ templatePath = getQwikTemplatePath(typescript, "component");
401
+ } else {
402
+ throw new Error(`Unsupported framework: ${framework}`);
403
+ }
404
+ return renderTemplate(templatePath, {
405
+ componentName,
406
+ formattedNodes,
407
+ typescript,
408
+ keepColors
409
+ });
410
+ }
411
+ function generateReactLikeBaseComponent(typescript, framework) {
412
+ let templatePath;
413
+ if (framework === "solid") {
414
+ templatePath = getSolidTemplatePath(typescript, "createIcon");
415
+ } else if (framework === "preact") {
416
+ templatePath = getPreactTemplatePath(typescript, "createIcon");
417
+ } else if (framework === "qwik") {
418
+ templatePath = getQwikTemplatePath(typescript, "createIcon");
419
+ } else {
420
+ throw new Error(`Unsupported framework: ${framework}`);
421
+ }
422
+ return {
423
+ code: renderTemplate(templatePath, { typescript }),
424
+ fileName: typescript ? "createIcon.tsx" : "createIcon.jsx"
425
+ };
426
+ }
427
+
428
+ // src/generators/svelte.ts
429
+ function generateSvelteComponent(_componentName, iconNode, typescript) {
430
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
431
+ const templatePath = getSvelteTemplatePath(typescript, "component");
432
+ return renderTemplate(templatePath, {
433
+ typescript,
434
+ formattedNodes
435
+ });
436
+ }
437
+ function generateSvelteIcon(typescript) {
438
+ const templatePath = getSvelteTemplatePath(typescript, "icon");
439
+ return renderTemplate(templatePath, { typescript });
440
+ }
441
+
442
+ // src/generators/vanilla.ts
443
+ function generateVanillaComponent(componentName, iconNode, typescript, keepColors) {
444
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
445
+ const templatePath = getVanillaTemplatePath(typescript, "component");
446
+ return renderTemplate(templatePath, {
447
+ componentName,
448
+ formattedNodes,
449
+ typescript,
450
+ keepColors
451
+ });
452
+ }
453
+ function generateVanillaBaseComponent(typescript) {
454
+ const templatePath = getVanillaTemplatePath(typescript, "createIcon");
455
+ return {
456
+ code: renderTemplate(templatePath, { typescript }),
457
+ fileName: typescript ? "createIcon.ts" : "createIcon.js"
458
+ };
459
+ }
460
+
461
+ // src/generators/vue.ts
462
+ function generateVueComponent(componentName, iconNode, typescript) {
463
+ const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
464
+ const templatePath = getVueTemplatePath(typescript, "component");
465
+ return renderTemplate(templatePath, {
466
+ typescript,
467
+ componentName,
468
+ formattedNodes
469
+ });
470
+ }
471
+ function generateVueIcon(typescript) {
472
+ const templatePath = getVueTemplatePath(typescript, "icon");
473
+ return renderTemplate(templatePath, { typescript });
474
+ }
475
+
476
+ // src/generators/framework-strategy.ts
477
+ var ReactStrategy = class {
478
+ constructor() {
479
+ this.name = "react";
480
+ this.getComponentExtension = (typescript) => {
481
+ return typescript ? "tsx" : "jsx";
482
+ };
483
+ this.getIndexExtension = (typescript) => {
484
+ return typescript ? "ts" : "js";
485
+ };
486
+ this.generateComponent = (componentName, iconNode, typescript, keepColors = false) => {
487
+ return generateReactComponent(componentName, iconNode, typescript, keepColors);
488
+ };
489
+ this.generateBaseComponent = (typescript) => {
490
+ return {
491
+ code: generateCreateIcon(typescript),
492
+ fileName: `createIcon.${this.getComponentExtension(typescript)}`
493
+ };
494
+ };
495
+ }
496
+ };
497
+ var VueStrategy = class {
498
+ constructor() {
499
+ this.name = "vue";
500
+ this.getComponentExtension = (_typescript) => {
501
+ return "vue";
502
+ };
503
+ this.getIndexExtension = (typescript) => {
504
+ return typescript ? "ts" : "js";
505
+ };
506
+ this.generateComponent = (componentName, iconNode, typescript) => {
507
+ return generateVueComponent(componentName, iconNode, typescript);
508
+ };
509
+ this.generateBaseComponent = (typescript) => {
510
+ return {
511
+ code: generateVueIcon(typescript),
512
+ fileName: "Icon.vue"
513
+ };
514
+ };
515
+ }
516
+ };
517
+ var SvelteStrategy = class {
518
+ constructor() {
519
+ this.name = "svelte";
520
+ this.getComponentExtension = (_typescript) => {
521
+ return "svelte";
522
+ };
523
+ this.getIndexExtension = (typescript) => {
524
+ return typescript ? "ts" : "js";
525
+ };
526
+ this.generateComponent = (componentName, iconNode, typescript) => {
527
+ return generateSvelteComponent(componentName, iconNode, typescript);
528
+ };
529
+ this.generateBaseComponent = (typescript) => {
530
+ return {
531
+ code: generateSvelteIcon(typescript),
532
+ fileName: "Icon.svelte"
533
+ };
534
+ };
535
+ }
536
+ };
537
+ var SolidStrategy = class {
538
+ constructor() {
539
+ this.name = "solid";
540
+ this.getComponentExtension = (typescript) => {
541
+ return typescript ? "tsx" : "jsx";
542
+ };
543
+ this.getIndexExtension = (typescript) => {
544
+ return typescript ? "ts" : "js";
545
+ };
546
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
547
+ return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "solid");
548
+ };
549
+ this.generateBaseComponent = (typescript) => {
550
+ return generateReactLikeBaseComponent(typescript, "solid");
551
+ };
552
+ }
553
+ };
554
+ var PreactStrategy = class {
555
+ constructor() {
556
+ this.name = "preact";
557
+ this.getComponentExtension = (typescript) => {
558
+ return typescript ? "tsx" : "jsx";
559
+ };
560
+ this.getIndexExtension = (typescript) => {
561
+ return typescript ? "ts" : "js";
562
+ };
563
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
564
+ return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "preact");
565
+ };
566
+ this.generateBaseComponent = (typescript) => {
567
+ return generateReactLikeBaseComponent(typescript, "preact");
568
+ };
569
+ }
570
+ };
571
+ var VanillaStrategy = class {
572
+ constructor() {
573
+ this.name = "vanilla";
574
+ this.getComponentExtension = (typescript) => {
575
+ return typescript ? "ts" : "js";
576
+ };
577
+ this.getIndexExtension = (typescript) => {
578
+ return typescript ? "ts" : "js";
579
+ };
580
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
581
+ return generateVanillaComponent(componentName, iconNode, typescript, keepColors ?? false);
582
+ };
583
+ this.generateBaseComponent = (typescript) => {
584
+ return generateVanillaBaseComponent(typescript);
585
+ };
586
+ }
587
+ };
588
+ var LitStrategy = class {
589
+ constructor() {
590
+ this.name = "lit";
591
+ this.getComponentExtension = (typescript) => {
592
+ return typescript ? "ts" : "js";
593
+ };
594
+ this.getIndexExtension = (typescript) => {
595
+ return typescript ? "ts" : "js";
596
+ };
597
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
598
+ return generateLitComponent(componentName, iconNode, typescript, keepColors ?? false);
599
+ };
600
+ this.generateBaseComponent = (typescript) => {
601
+ return generateLitBaseComponent(typescript);
602
+ };
603
+ }
604
+ };
605
+ var QwikStrategy = class {
606
+ constructor() {
607
+ this.name = "qwik";
608
+ this.getComponentExtension = (typescript) => {
609
+ return typescript ? "tsx" : "jsx";
610
+ };
611
+ this.getIndexExtension = (typescript) => {
612
+ return typescript ? "ts" : "js";
613
+ };
614
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
615
+ return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "qwik");
616
+ };
617
+ this.generateBaseComponent = (typescript) => {
618
+ return generateReactLikeBaseComponent(typescript, "qwik");
619
+ };
620
+ }
621
+ };
622
+ var AstroStrategy = class {
623
+ constructor() {
624
+ this.name = "astro";
625
+ this.getComponentExtension = (_typescript) => {
626
+ return "astro";
627
+ };
628
+ this.getIndexExtension = (typescript) => {
629
+ return typescript ? "ts" : "js";
630
+ };
631
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
632
+ return generateAstroComponent(componentName, iconNode, typescript, keepColors ?? false);
633
+ };
634
+ this.generateBaseComponent = (typescript) => {
635
+ return generateAstroBaseComponent(typescript);
636
+ };
637
+ }
638
+ };
639
+ var AngularStrategy = class {
640
+ constructor() {
641
+ this.name = "angular";
642
+ this.getComponentExtension = (_typescript) => {
643
+ return "ts";
644
+ };
645
+ this.getIndexExtension = (_typescript) => {
646
+ return "ts";
647
+ };
648
+ this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
649
+ return generateAngularComponent(componentName, iconNode, typescript, keepColors ?? false);
650
+ };
651
+ this.generateBaseComponent = (typescript) => {
652
+ return generateAngularBaseComponent(typescript);
653
+ };
654
+ }
655
+ };
656
+ var FrameworkRegistry = class {
657
+ constructor() {
658
+ this.strategies = /* @__PURE__ */ new Map();
659
+ this.register(new ReactStrategy());
660
+ this.register(new VueStrategy());
661
+ this.register(new SvelteStrategy());
662
+ this.register(new SolidStrategy());
663
+ this.register(new PreactStrategy());
664
+ this.register(new VanillaStrategy());
665
+ this.register(new LitStrategy());
666
+ this.register(new QwikStrategy());
667
+ this.register(new AstroStrategy());
668
+ this.register(new AngularStrategy());
669
+ }
670
+ /**
671
+ * Register a framework strategy
672
+ */
673
+ register(strategy) {
674
+ this.strategies.set(strategy.name, strategy);
675
+ }
676
+ /**
677
+ * Get a framework strategy
678
+ */
679
+ get(framework) {
680
+ const strategy = this.strategies.get(framework);
681
+ if (!strategy) {
682
+ throw new Error(`Unsupported framework: ${framework}`);
683
+ }
684
+ return strategy;
685
+ }
686
+ /**
687
+ * Check if a framework is supported
688
+ */
689
+ has(framework) {
690
+ return this.strategies.has(framework);
691
+ }
692
+ /**
693
+ * Get all supported frameworks
694
+ */
695
+ getSupportedFrameworks() {
696
+ return Array.from(this.strategies.keys());
697
+ }
698
+ };
699
+ var frameworkRegistry = new FrameworkRegistry();
700
+ function getFrameworkStrategy(framework) {
701
+ return frameworkRegistry.get(framework);
702
+ }
703
+
704
+ // src/config/loader.ts
705
+ var DEFAULT_CONFIG = {
706
+ input: "./icons",
707
+ output: "./src/icons",
708
+ typescript: true,
709
+ optimize: true,
710
+ keepColors: false,
711
+ prefix: "",
712
+ suffix: "",
713
+ configDir: ".",
714
+ generateOptions: {
715
+ index: true,
716
+ types: true,
717
+ preview: false,
718
+ cleanOutput: false
719
+ },
720
+ watch: {
721
+ enabled: false,
722
+ ignore: ["**/node_modules/**", "**/.git/**"],
723
+ debounce: 300
724
+ }
725
+ };
726
+ async function loadConfig(configPath) {
727
+ const absolutePath = import_node_path2.default.resolve(import_node_process.default.cwd(), configPath);
728
+ const configDir = import_node_path2.default.dirname(absolutePath);
729
+ const jiti = (0, import_jiti.createJiti)(configDir, {
730
+ interopDefault: true
731
+ });
732
+ let config;
733
+ try {
734
+ config = await jiti.import(absolutePath);
735
+ } catch (error) {
736
+ throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
737
+ }
738
+ let loadedConfig = config.default || config;
739
+ if (Array.isArray(loadedConfig)) {
740
+ loadedConfig = loadedConfig[0];
741
+ }
742
+ const mergedConfig = {
743
+ ...DEFAULT_CONFIG,
744
+ ...loadedConfig,
745
+ generateOptions: {
746
+ ...DEFAULT_CONFIG.generateOptions,
747
+ ...loadedConfig.generateOptions
748
+ },
749
+ watch: {
750
+ ...DEFAULT_CONFIG.watch,
751
+ ...loadedConfig.watch
752
+ }
753
+ };
754
+ if (mergedConfig.configDir && mergedConfig.configDir !== ".") {
755
+ const projectRoot = import_node_path2.default.resolve(configDir, mergedConfig.configDir);
756
+ mergedConfig.input = import_node_path2.default.resolve(projectRoot, mergedConfig.input);
757
+ mergedConfig.output = import_node_path2.default.resolve(projectRoot, mergedConfig.output);
758
+ } else {
759
+ mergedConfig.input = import_node_path2.default.resolve(configDir, mergedConfig.input);
760
+ mergedConfig.output = import_node_path2.default.resolve(configDir, mergedConfig.output);
761
+ }
762
+ if (!mergedConfig.framework) {
763
+ const supported = frameworkRegistry.getSupportedFrameworks().join(", ");
764
+ throw new Error(`Config must specify a framework (${supported})`);
765
+ }
766
+ if (!frameworkRegistry.has(mergedConfig.framework)) {
767
+ const supported = frameworkRegistry.getSupportedFrameworks().join(", ");
768
+ throw new Error(`Invalid framework: ${mergedConfig.framework}. Supported: ${supported}`);
769
+ }
770
+ return mergedConfig;
771
+ }
772
+ async function findConfig() {
773
+ const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_helpers(), helpers_exports));
774
+ const configFiles = [
775
+ "vectify.config.ts",
776
+ "vectify.config.js"
777
+ ];
778
+ for (const file of configFiles) {
779
+ const configPath = import_node_path2.default.resolve(import_node_process.default.cwd(), file);
780
+ if (await fileExists2(configPath)) {
781
+ return configPath;
782
+ }
783
+ }
784
+ return null;
785
+ }
786
+
787
+ // src/generators/index.ts
788
+ var import_node_path3 = __toESM(require("path"));
789
+
790
+ // src/parsers/optimizer.ts
791
+ var import_svgo = require("svgo");
792
+ var DEFAULT_SVGO_CONFIG = {
793
+ plugins: [
794
+ "preset-default",
795
+ "removeViewBox",
796
+ "removeDimensions",
797
+ "convertShapeToPath",
798
+ {
799
+ name: "removeAttrs",
800
+ params: {
801
+ attrs: ["class", "data-name"]
802
+ }
803
+ }
804
+ ]
805
+ };
806
+ async function optimizeSvg(svgContent, config) {
807
+ if (!config.optimize) {
808
+ return svgContent;
809
+ }
810
+ try {
811
+ const result = (0, import_svgo.optimize)(svgContent, {
812
+ ...DEFAULT_SVGO_CONFIG,
813
+ ...config.svgoConfig
814
+ });
815
+ return result.data;
816
+ } catch (error) {
817
+ console.warn(`SVGO optimization failed: ${error.message}`);
818
+ return svgContent;
819
+ }
820
+ }
821
+
822
+ // src/generators/index.ts
823
+ init_helpers();
824
+ async function generateIcons(config, dryRun = false) {
825
+ const stats = {
826
+ success: 0,
827
+ failed: 0,
828
+ total: 0,
829
+ errors: []
830
+ };
831
+ try {
832
+ if (!dryRun) {
833
+ await ensureDir(config.output);
834
+ }
835
+ const svgFiles = await getSvgFiles(config.input);
836
+ stats.total = svgFiles.length;
837
+ if (svgFiles.length === 0) {
838
+ console.warn(`No SVG files found in ${config.input}`);
839
+ return stats;
840
+ }
841
+ if (config.generateOptions?.cleanOutput && !dryRun) {
842
+ await cleanOutputDirectory(svgFiles, config);
843
+ }
844
+ await generateBaseComponent(config, dryRun);
845
+ for (const svgFile of svgFiles) {
846
+ try {
847
+ await generateIconComponent(svgFile, config, dryRun);
848
+ stats.success++;
849
+ } catch (error) {
850
+ stats.failed++;
851
+ stats.errors.push({
852
+ file: svgFile,
853
+ error: error.message
854
+ });
855
+ console.error(`Failed to generate ${svgFile}: ${error.message}`);
856
+ }
857
+ }
858
+ if (config.generateOptions?.index) {
859
+ await generateIndexFile(svgFiles, config, dryRun);
860
+ }
861
+ if (config.generateOptions?.preview && !dryRun) {
862
+ await generatePreviewHtml(svgFiles, config);
863
+ }
864
+ if (config.hooks?.onComplete) {
865
+ await config.hooks.onComplete(stats);
866
+ }
867
+ } catch (error) {
868
+ throw new Error(`Generation failed: ${error.message}`);
869
+ }
870
+ return stats;
871
+ }
872
+ async function generateIconComponent(svgFile, config, dryRun = false) {
873
+ let svgContent = await readFile(svgFile);
874
+ const fileName = import_node_path3.default.basename(svgFile);
875
+ if (config.hooks?.beforeParse) {
876
+ svgContent = await config.hooks.beforeParse(svgContent, fileName);
877
+ }
878
+ svgContent = await optimizeSvg(svgContent, config);
879
+ const iconNode = parseSvg(svgContent);
880
+ const componentName = getComponentName(
881
+ fileName,
882
+ config.prefix,
883
+ config.suffix,
884
+ config.transform
885
+ );
886
+ const strategy = getFrameworkStrategy(config.framework);
887
+ const typescript = config.typescript ?? true;
888
+ let code = strategy.generateComponent(
889
+ componentName,
890
+ iconNode,
891
+ typescript,
892
+ config.keepColors ?? false
893
+ );
894
+ if (config.hooks?.afterGenerate) {
895
+ code = await config.hooks.afterGenerate(code, componentName);
896
+ }
897
+ const fileExt = strategy.getComponentExtension(typescript);
898
+ const outputPath = import_node_path3.default.join(config.output, `${componentName}.${fileExt}`);
899
+ if (dryRun) {
900
+ console.log(` ${componentName}.${fileExt}`);
901
+ } else {
902
+ await writeFile(outputPath, code);
903
+ }
904
+ }
905
+ async function generateBaseComponent(config, dryRun = false) {
906
+ const typescript = config.typescript ?? true;
907
+ const strategy = getFrameworkStrategy(config.framework);
908
+ const { code, fileName } = strategy.generateBaseComponent(typescript);
909
+ const outputPath = import_node_path3.default.join(config.output, fileName);
910
+ if (dryRun) {
911
+ console.log(` ${fileName}`);
912
+ } else {
913
+ await writeFile(outputPath, code);
914
+ }
915
+ }
916
+ async function generateIndexFile(svgFiles, config, dryRun = false) {
917
+ const typescript = config.typescript ?? true;
918
+ const strategy = getFrameworkStrategy(config.framework);
919
+ const ext = strategy.getIndexExtension(typescript);
920
+ const usesDefaultExport = config.framework === "vue" || config.framework === "svelte" || config.framework === "preact";
921
+ const exports2 = svgFiles.map((svgFile) => {
922
+ const fileName = import_node_path3.default.basename(svgFile);
923
+ const componentName = getComponentName(
924
+ fileName,
925
+ config.prefix,
926
+ config.suffix,
927
+ config.transform
928
+ );
929
+ if (usesDefaultExport) {
930
+ return `export { default as ${componentName} } from './${componentName}'`;
931
+ } else {
932
+ return `export { ${componentName} } from './${componentName}'`;
933
+ }
934
+ }).join("\n");
935
+ const indexPath = import_node_path3.default.join(config.output, `index.${ext}`);
936
+ if (dryRun) {
937
+ console.log(` index.${ext}`);
938
+ } else {
939
+ await writeFile(indexPath, `${exports2}
940
+ `);
941
+ }
942
+ }
943
+ async function generatePreviewHtml(svgFiles, config) {
944
+ const componentNames = svgFiles.map((svgFile) => {
945
+ const fileName = import_node_path3.default.basename(svgFile);
946
+ return getComponentName(
947
+ fileName,
948
+ config.prefix,
949
+ config.suffix,
950
+ config.transform
951
+ );
952
+ });
953
+ const svgContents = await Promise.all(
954
+ svgFiles.map(async (svgFile) => {
955
+ return await readFile(svgFile);
956
+ })
957
+ );
958
+ const html = `<!DOCTYPE html>
959
+ <html lang="en">
960
+ <head>
961
+ <meta charset="UTF-8">
962
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
963
+ <title>Icons - ${componentNames.length} Total</title>
964
+ <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
965
+ </head>
966
+ <body class="bg-white">
967
+ <div class="max-w-[1400px] mx-auto px-6 py-12">
968
+ <header class="mb-12">
969
+ <h1 class="text-3xl font-semibold text-gray-900 mb-2">Icons</h1>
970
+ <p class="text-sm text-gray-600">${componentNames.length} icons \u2022 ${config.framework} \u2022 Click to copy name</p>
971
+ </header>
972
+
973
+ <div class="flex items-center gap-4 mb-8 pb-6 border-b border-gray-200">
974
+ <div class="flex-1">
975
+ <input
976
+ type="search"
977
+ id="search"
978
+ placeholder="Search icons..."
979
+ class="w-full h-10 px-4 text-sm border border-gray-300 rounded-lg focus:outline-none focus:border-gray-900 transition-colors"
980
+ />
981
+ </div>
982
+
983
+ <div class="flex items-center gap-3">
984
+ <label for="size" class="text-sm text-gray-600">Size</label>
985
+ <input
986
+ type="range"
987
+ id="size"
988
+ min="16"
989
+ max="96"
990
+ value="32"
991
+ step="8"
992
+ class="w-24 h-1 accent-gray-900"
993
+ />
994
+ <span id="sizeValue" class="text-sm text-gray-900 w-10">32px</span>
995
+ </div>
996
+
997
+ <div class="flex items-center gap-3">
998
+ <label for="color" class="text-sm text-gray-600">Color</label>
999
+ <input
1000
+ type="color"
1001
+ id="color"
1002
+ value="#171717"
1003
+ class="w-10 h-10 rounded-lg border border-gray-300 cursor-pointer"
1004
+ />
1005
+ </div>
1006
+ </div>
1007
+
1008
+ <div id="iconGrid" class="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 lg:grid-cols-10 xl:grid-cols-12 gap-1"></div>
1009
+ </div>
1010
+
1011
+ <script>
1012
+ const icons = ${JSON.stringify(componentNames)};
1013
+ const svgContents = ${JSON.stringify(svgContents)};
1014
+
1015
+ let currentSize = 32;
1016
+ let currentColor = '#171717';
1017
+ let searchQuery = '';
1018
+
1019
+ function renderIcons() {
1020
+ const grid = document.getElementById('iconGrid');
1021
+ grid.innerHTML = '';
1022
+
1023
+ const filteredIcons = icons.filter((name) =>
1024
+ name.toLowerCase().includes(searchQuery.toLowerCase())
1025
+ );
1026
+
1027
+ if (filteredIcons.length === 0) {
1028
+ grid.innerHTML = '<div class="col-span-full text-center py-20 text-gray-400 text-sm">No icons found</div>';
1029
+ return;
1030
+ }
1031
+
1032
+ for (let i = 0; i < filteredIcons.length; i++) {
1033
+ const iconName = filteredIcons[i];
1034
+ const svgIndex = icons.indexOf(iconName);
1035
+ const svgContent = svgContents[svgIndex];
1036
+
1037
+ const card = document.createElement('div');
1038
+ card.className = 'group relative aspect-square flex flex-col items-center justify-center p-4 rounded-lg border border-transparent hover:border-gray-200 hover:bg-gray-50 transition-all cursor-pointer';
1039
+ card.onclick = () => copyToClipboard(iconName);
1040
+ card.title = iconName;
1041
+
1042
+ const wrapper = document.createElement('div');
1043
+ wrapper.className = 'flex items-center justify-center mb-2';
1044
+
1045
+ wrapper.innerHTML = svgContent;
1046
+
1047
+ const svg = wrapper.querySelector('svg');
1048
+ if (svg) {
1049
+ svg.setAttribute('width', currentSize);
1050
+ svg.setAttribute('height', currentSize);
1051
+ svg.setAttribute('stroke', currentColor);
1052
+ svg.setAttribute('fill', 'none');
1053
+
1054
+ // Update stroke color for all child elements
1055
+ const elements = svg.querySelectorAll('[stroke]');
1056
+ elements.forEach(el => {
1057
+ el.setAttribute('stroke', currentColor);
1058
+ });
1059
+ }
1060
+
1061
+ const name = document.createElement('div');
1062
+ name.className = 'text-[10px] text-gray-500 text-center truncate w-full group-hover:text-gray-900';
1063
+ name.textContent = iconName;
1064
+
1065
+ card.appendChild(wrapper);
1066
+ card.appendChild(name);
1067
+ grid.appendChild(card);
1068
+ }
1069
+ }
1070
+
1071
+ function copyToClipboard(text) {
1072
+ navigator.clipboard.writeText(text).then(() => {
1073
+ showCopiedNotification(text);
1074
+ });
1075
+ }
1076
+
1077
+ function showCopiedNotification(text) {
1078
+ const existing = document.querySelector('.toast');
1079
+ if (existing) existing.remove();
1080
+
1081
+ const notification = document.createElement('div');
1082
+ notification.className = 'toast fixed bottom-6 right-6 bg-gray-900 text-white text-sm px-4 py-2.5 rounded-lg shadow-lg flex items-center gap-2 transition-opacity';
1083
+ notification.innerHTML = \`
1084
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1085
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
1086
+ </svg>
1087
+ <span>Copied \${text}</span>
1088
+ \`;
1089
+ document.body.appendChild(notification);
1090
+
1091
+ setTimeout(() => {
1092
+ notification.style.opacity = '0';
1093
+ setTimeout(() => notification.remove(), 200);
1094
+ }, 1800);
1095
+ }
1096
+
1097
+ document.getElementById('size').addEventListener('input', (e) => {
1098
+ currentSize = e.target.value;
1099
+ document.getElementById('sizeValue').textContent = currentSize + 'px';
1100
+ renderIcons();
1101
+ });
1102
+
1103
+ document.getElementById('color').addEventListener('input', (e) => {
1104
+ currentColor = e.target.value;
1105
+ renderIcons();
1106
+ });
1107
+
1108
+ document.getElementById('search').addEventListener('input', (e) => {
1109
+ searchQuery = e.target.value;
1110
+ renderIcons();
1111
+ });
1112
+
1113
+ renderIcons();
1114
+ </script>
1115
+ </body>
1116
+ </html>`;
1117
+ const previewPath = import_node_path3.default.join(config.output, "preview.html");
1118
+ await writeFile(previewPath, html);
1119
+ }
1120
+ async function cleanOutputDirectory(svgFiles, config) {
1121
+ const { readdir, unlink } = await import("fs/promises");
1122
+ const strategy = getFrameworkStrategy(config.framework);
1123
+ const fileExt = strategy.getComponentExtension(config.typescript ?? true);
1124
+ const expectedComponents = new Set(
1125
+ svgFiles.map((svgFile) => {
1126
+ const fileName = import_node_path3.default.basename(svgFile, ".svg");
1127
+ const componentName = getComponentName(
1128
+ fileName,
1129
+ config.prefix,
1130
+ config.suffix,
1131
+ config.transform
1132
+ );
1133
+ return `${componentName}.${fileExt}`;
1134
+ })
1135
+ );
1136
+ const protectedFiles = /* @__PURE__ */ new Set([
1137
+ `Icon.${fileExt}`,
1138
+ `createIcon.${fileExt}`,
1139
+ `index.${config.typescript ? "ts" : "js"}`,
1140
+ `index.d.ts`,
1141
+ "preview.html"
1142
+ ]);
1143
+ try {
1144
+ const files = await readdir(config.output);
1145
+ for (const file of files) {
1146
+ if (protectedFiles.has(file)) {
1147
+ continue;
1148
+ }
1149
+ if (!file.endsWith(`.${fileExt}`)) {
1150
+ continue;
1151
+ }
1152
+ if (!expectedComponents.has(file)) {
1153
+ const filePath = import_node_path3.default.join(config.output, file);
1154
+ await unlink(filePath);
1155
+ console.log(`Deleted orphaned component: ${file}`);
1156
+ }
1157
+ }
1158
+ } catch (error) {
1159
+ console.warn(`Failed to clean output directory: ${error.message}`);
1160
+ }
1161
+ }
1162
+
1163
+ // src/commands/generate.ts
1164
+ async function generate(options = {}) {
1165
+ const spinner = (0, import_ora.default)("Loading configuration...").start();
1166
+ try {
1167
+ let configPath = options.config;
1168
+ if (!configPath) {
1169
+ const foundConfig = await findConfig();
1170
+ if (!foundConfig) {
1171
+ spinner.fail("No config file found");
1172
+ console.log(import_chalk.default.yellow("\nRun"), import_chalk.default.cyan("svg-icon init"), import_chalk.default.yellow("to create a config file"));
1173
+ return;
1174
+ }
1175
+ configPath = foundConfig;
1176
+ }
1177
+ const config = await loadConfig(configPath);
1178
+ spinner.succeed(`Config loaded from ${import_chalk.default.green(configPath)}`);
1179
+ if (options.dryRun) {
1180
+ spinner.info(import_chalk.default.cyan("Dry run mode - no files will be written"));
1181
+ console.log(`
1182
+ ${import_chalk.default.bold("Files that would be generated:")}
1183
+ `);
1184
+ }
1185
+ const actionText = options.dryRun ? "Analyzing icons..." : "Generating icon components...";
1186
+ spinner.start(actionText);
1187
+ const stats = await generateIcons(config, options.dryRun);
1188
+ if (stats.failed > 0) {
1189
+ spinner.warn(`${options.dryRun ? "Analyzed" : "Generated"} ${import_chalk.default.green(stats.success)} icons, ${import_chalk.default.red(stats.failed)} failed`);
1190
+ if (stats.errors.length > 0) {
1191
+ console.log(`
1192
+ ${import_chalk.default.bold.red("Errors:")}`);
1193
+ stats.errors.forEach(({ file, error }) => {
1194
+ console.log(` ${import_chalk.default.red("\u2717")} ${file}: ${error}`);
1195
+ });
1196
+ }
1197
+ } else {
1198
+ const message = options.dryRun ? `Would generate ${import_chalk.default.green(stats.success)} icon components` : `Generated ${import_chalk.default.green(stats.success)} icon components`;
1199
+ spinner.succeed(message);
1200
+ }
1201
+ if (options.dryRun) {
1202
+ console.log(`
1203
+ ${import_chalk.default.bold("Target directory:")} ${import_chalk.default.cyan(config.output)}`);
1204
+ console.log(import_chalk.default.gray("\nRun without --dry-run to generate files"));
1205
+ } else {
1206
+ console.log(`
1207
+ ${import_chalk.default.bold("Output:")} ${import_chalk.default.cyan(config.output)}`);
1208
+ if (config.generateOptions?.preview) {
1209
+ console.log(`${import_chalk.default.bold("Preview:")} ${import_chalk.default.cyan(`${config.output}/preview.html`)}`);
1210
+ }
1211
+ }
1212
+ } catch (error) {
1213
+ spinner.fail("Generation failed");
1214
+ console.error(import_chalk.default.red(error.message));
1215
+ throw error;
1216
+ }
1217
+ }
1218
+
1219
+ // src/commands/init.ts
1220
+ var import_node_path4 = __toESM(require("path"));
1221
+ var import_node_process2 = __toESM(require("process"));
1222
+ var import_chalk2 = __toESM(require("chalk"));
1223
+ var import_inquirer = __toESM(require("inquirer"));
1224
+ var import_ora2 = __toESM(require("ora"));
1225
+ init_helpers();
1226
+ async function init(options = {}) {
1227
+ try {
1228
+ const projectRoot = await findProjectRoot();
1229
+ const currentDir = import_node_process2.default.cwd();
1230
+ if (currentDir !== projectRoot) {
1231
+ console.log(import_chalk2.default.yellow(`
1232
+ Note: Project root detected at ${import_chalk2.default.cyan(projectRoot)}`));
1233
+ console.log(import_chalk2.default.yellow(`Current directory: ${import_chalk2.default.cyan(currentDir)}
1234
+ `));
1235
+ }
1236
+ const pathAnswers = await import_inquirer.default.prompt([
1237
+ {
1238
+ type: "input",
1239
+ name: "configPath",
1240
+ message: "Where should we create the config file?",
1241
+ default: options.config || "./vectify.config.ts",
1242
+ validate: (input) => {
1243
+ if (!input.endsWith(".ts") && !input.endsWith(".js")) {
1244
+ return "Config file must have .ts or .js extension";
1245
+ }
1246
+ return true;
1247
+ }
1248
+ }
1249
+ ]);
1250
+ const configPath = import_node_path4.default.resolve(projectRoot, pathAnswers.configPath);
1251
+ const configDir = import_node_path4.default.dirname(configPath);
1252
+ if (!options.force && await fileExists(configPath)) {
1253
+ const { overwrite } = await import_inquirer.default.prompt([
1254
+ {
1255
+ type: "confirm",
1256
+ name: "overwrite",
1257
+ message: "Config file already exists. Overwrite?",
1258
+ default: false
1259
+ }
1260
+ ]);
1261
+ if (!overwrite) {
1262
+ console.log(import_chalk2.default.yellow("Cancelled"));
1263
+ return;
1264
+ }
1265
+ }
1266
+ const supportedFrameworks = frameworkRegistry.getSupportedFrameworks();
1267
+ const frameworkChoices = supportedFrameworks.map((fw) => ({
1268
+ name: fw.charAt(0).toUpperCase() + fw.slice(1),
1269
+ value: fw
1270
+ }));
1271
+ const answers = await import_inquirer.default.prompt([
1272
+ {
1273
+ type: "list",
1274
+ name: "framework",
1275
+ message: "Which framework are you using?",
1276
+ choices: frameworkChoices
1277
+ },
1278
+ {
1279
+ type: "input",
1280
+ name: "input",
1281
+ message: "Where are your SVG files located?",
1282
+ default: "./icons"
1283
+ },
1284
+ {
1285
+ type: "input",
1286
+ name: "output",
1287
+ message: "Where should we output the components?",
1288
+ default: "./src/icons"
1289
+ },
1290
+ {
1291
+ type: "confirm",
1292
+ name: "typescript",
1293
+ message: "Use TypeScript?",
1294
+ default: true
1295
+ },
1296
+ {
1297
+ type: "confirm",
1298
+ name: "optimize",
1299
+ message: "Optimize SVG files with SVGO?",
1300
+ default: true
1301
+ },
1302
+ {
1303
+ type: "input",
1304
+ name: "prefix",
1305
+ message: "Component name prefix (optional):",
1306
+ default: ""
1307
+ },
1308
+ {
1309
+ type: "input",
1310
+ name: "suffix",
1311
+ message: "Component name suffix (optional):",
1312
+ default: ""
1313
+ }
1314
+ ]);
1315
+ const inputPath = import_node_path4.default.resolve(projectRoot, answers.input);
1316
+ const outputPath = import_node_path4.default.resolve(projectRoot, answers.output);
1317
+ const spinner = (0, import_ora2.default)("Setting up directories...").start();
1318
+ await ensureDir(inputPath);
1319
+ spinner.text = `Created input directory: ${import_chalk2.default.cyan(answers.input)}`;
1320
+ await ensureDir(outputPath);
1321
+ spinner.succeed(`Created output directory: ${import_chalk2.default.cyan(answers.output)}`);
1322
+ const relativeConfigDir = import_node_path4.default.relative(configDir, projectRoot) || ".";
1323
+ const configContent = generateConfigContent(answers, relativeConfigDir);
1324
+ spinner.start("Creating config file...");
1325
+ await writeFile(configPath, configContent);
1326
+ spinner.succeed(`Config file created at ${import_chalk2.default.green(configPath)}`);
1327
+ console.log(`
1328
+ ${import_chalk2.default.bold("Next steps:")}`);
1329
+ console.log(` 1. Place your SVG files in ${import_chalk2.default.cyan(answers.input)}`);
1330
+ console.log(` 2. Run ${import_chalk2.default.cyan("svg-icon generate")} to generate components`);
1331
+ console.log(` 3. Import and use your icons!
1332
+ `);
1333
+ } catch (error) {
1334
+ console.error(import_chalk2.default.red("Initialization failed"));
1335
+ throw error;
1336
+ }
1337
+ }
1338
+ function generateConfigContent(answers, configDir) {
1339
+ return `import { defineConfig } from 'vectify'
1340
+
1341
+ export default defineConfig({
1342
+ framework: '${answers.framework}',
1343
+ configDir: '${configDir}',
1344
+ input: '${answers.input}',
1345
+ output: '${answers.output}',
1346
+ typescript: ${answers.typescript},
1347
+ optimize: ${answers.optimize},
1348
+ prefix: '${answers.prefix}',
1349
+ suffix: '${answers.suffix}',
1350
+ generateOptions: {
1351
+ index: true,
1352
+ types: true,
1353
+ preview: false
1354
+ },
1355
+ watch: {
1356
+ enabled: false,
1357
+ ignore: ['**/node_modules/**', '**/.git/**'],
1358
+ debounce: 300,
1359
+ },
1360
+ })
1361
+ `;
1362
+ }
1363
+
1364
+ // src/commands/watch.ts
1365
+ var import_node_path5 = __toESM(require("path"));
1366
+ var import_chalk3 = __toESM(require("chalk"));
1367
+ var import_chokidar = __toESM(require("chokidar"));
1368
+ var import_ora3 = __toESM(require("ora"));
1369
+ async function watch(options = {}) {
1370
+ const spinner = (0, import_ora3.default)("Loading configuration...").start();
1371
+ try {
1372
+ let configPath = options.config;
1373
+ if (!configPath) {
1374
+ const foundConfig = await findConfig();
1375
+ if (!foundConfig) {
1376
+ spinner.fail("No config file found");
1377
+ console.log(import_chalk3.default.yellow("\nRun"), import_chalk3.default.cyan("svg-icon init"), import_chalk3.default.yellow("to create a config file"));
1378
+ return;
1379
+ }
1380
+ configPath = foundConfig;
1381
+ }
1382
+ const config = await loadConfig(configPath);
1383
+ spinner.succeed(`Config loaded from ${import_chalk3.default.green(configPath)}`);
1384
+ spinner.start("Generating icon components...");
1385
+ const initialStats = await generateIcons(config);
1386
+ spinner.succeed(`Generated ${import_chalk3.default.green(initialStats.success)} icon components`);
1387
+ const watchPath = import_node_path5.default.join(config.input, "**/*.svg");
1388
+ const debounce = config.watch?.debounce ?? 300;
1389
+ const ignore = config.watch?.ignore ?? ["**/node_modules/**", "**/.git/**"];
1390
+ console.log(import_chalk3.default.bold("\nWatching for changes..."));
1391
+ console.log(` ${import_chalk3.default.cyan(watchPath)}`);
1392
+ console.log(` ${import_chalk3.default.gray("Press Ctrl+C to stop")}
1393
+ `);
1394
+ const debounceTimer = null;
1395
+ const watcher = import_chokidar.default.watch(watchPath, {
1396
+ ignored: ignore,
1397
+ persistent: true,
1398
+ ignoreInitial: true
1399
+ });
1400
+ watcher.on("add", (filePath) => {
1401
+ handleChange("added", filePath, config, debounce, debounceTimer);
1402
+ }).on("change", (filePath) => {
1403
+ handleChange("changed", filePath, config, debounce, debounceTimer);
1404
+ }).on("unlink", (filePath) => {
1405
+ console.log(import_chalk3.default.yellow(`SVG file removed: ${import_node_path5.default.basename(filePath)}`));
1406
+ handleChange("removed", filePath, config, debounce, debounceTimer);
1407
+ }).on("error", (error) => {
1408
+ console.error(import_chalk3.default.red(`Watcher error: ${error.message}`));
1409
+ });
1410
+ process.on("SIGINT", () => {
1411
+ console.log(`
1412
+
1413
+ ${import_chalk3.default.yellow("Stopping watch mode...")}`);
1414
+ watcher.close();
1415
+ process.exit(0);
1416
+ });
1417
+ } catch (error) {
1418
+ spinner.fail("Watch mode failed");
1419
+ console.error(import_chalk3.default.red(error.message));
1420
+ throw error;
1421
+ }
1422
+ }
1423
+ function handleChange(event, filePath, config, debounce, timer) {
1424
+ const fileName = import_node_path5.default.basename(filePath);
1425
+ if (timer) {
1426
+ clearTimeout(timer);
1427
+ }
1428
+ timer = setTimeout(async () => {
1429
+ const spinner = (0, import_ora3.default)(`Regenerating icons...`).start();
1430
+ try {
1431
+ const stats = await generateIcons(config);
1432
+ if (stats.failed > 0) {
1433
+ spinner.warn(
1434
+ `Regenerated ${import_chalk3.default.green(stats.success)} icons, ${import_chalk3.default.red(stats.failed)} failed`
1435
+ );
1436
+ } else {
1437
+ spinner.succeed(`Regenerated ${import_chalk3.default.green(stats.success)} icon components`);
1438
+ }
1439
+ console.log(import_chalk3.default.gray(` Triggered by: ${fileName} (${event})
1440
+ `));
1441
+ } catch (error) {
1442
+ spinner.fail("Regeneration failed");
1443
+ console.error(import_chalk3.default.red(error.message));
1444
+ }
1445
+ }, debounce);
1446
+ }
1447
+
1448
+ // src/types.ts
1449
+ function defineConfig(config) {
1450
+ return config;
1451
+ }
1452
+ // Annotate the CommonJS export names for ESM import in node:
1453
+ 0 && (module.exports = {
1454
+ defineConfig,
1455
+ findConfig,
1456
+ frameworkRegistry,
1457
+ generate,
1458
+ generateIcons,
1459
+ getFrameworkStrategy,
1460
+ init,
1461
+ loadConfig,
1462
+ watch
1463
+ });