vectify 2.0.5 → 2.1.1
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/README.md +12 -13
- package/README.zh-CN.md +12 -13
- package/dist/{chunk-CIKTK6HI.mjs → chunk-FS34P27H.mjs} +8 -0
- package/dist/{chunk-GY4VNET5.mjs → chunk-QYE23M3E.mjs} +625 -65
- package/dist/cli.js +676 -117
- package/dist/cli.mjs +3 -3
- package/dist/{helpers-UPZEBRGK.mjs → helpers-ZOR3OD66.mjs} +1 -1
- package/dist/index.d.mts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +669 -110
- package/dist/index.mjs +2 -2
- package/dist/templates/angular/component.ts.hbs +11 -2
- package/dist/templates/angular/createIcon.ts.hbs +11 -2
- package/dist/templates/astro/component.astro.hbs +12 -2
- package/dist/templates/astro/createIcon.astro.hbs +12 -2
- package/dist/templates/lit/component.js.hbs +1 -0
- package/dist/templates/lit/component.ts.hbs +1 -0
- package/dist/templates/lit/createIcon.js.hbs +12 -2
- package/dist/templates/lit/createIcon.ts.hbs +12 -2
- package/dist/templates/preact/component.jsx.hbs +1 -1
- package/dist/templates/preact/component.tsx.hbs +1 -1
- package/dist/templates/preact/createIcon.jsx.hbs +12 -3
- package/dist/templates/preact/createIcon.tsx.hbs +13 -3
- package/dist/templates/qwik/component.jsx.hbs +1 -1
- package/dist/templates/qwik/component.tsx.hbs +1 -1
- package/dist/templates/qwik/createIcon.jsx.hbs +12 -3
- package/dist/templates/qwik/createIcon.tsx.hbs +13 -3
- package/dist/templates/react/component.jsx.hbs +1 -1
- package/dist/templates/react/component.tsx.hbs +1 -1
- package/dist/templates/react/createIcon.jsx.hbs +12 -3
- package/dist/templates/react/createIcon.tsx.hbs +13 -3
- package/dist/templates/solid/component.tsx.hbs +1 -1
- package/dist/templates/solid/createIcon.jsx.hbs +13 -3
- package/dist/templates/solid/createIcon.tsx.hbs +14 -3
- package/dist/templates/svelte/component.js.svelte.hbs +4 -1
- package/dist/templates/svelte/component.ts.svelte.hbs +4 -1
- package/dist/templates/svelte/icon.js.svelte.hbs +23 -2
- package/dist/templates/svelte/icon.ts.svelte.hbs +23 -2
- package/dist/templates/vanilla/component.ts.hbs +1 -1
- package/dist/templates/vanilla/createIcon.js.hbs +12 -3
- package/dist/templates/vanilla/createIcon.ts.hbs +13 -3
- package/dist/templates/vue/component.js.vue.hbs +5 -2
- package/dist/templates/vue/component.ts.vue.hbs +5 -2
- package/dist/templates/vue/icon.js.vue.hbs +26 -2
- package/dist/templates/vue/icon.ts.vue.hbs +26 -2
- package/dist/templates/vue2/component.js.vue.hbs +4 -2
- package/dist/templates/vue2/component.ts.vue.hbs +5 -2
- package/dist/templates/vue2/icon.js.vue.hbs +25 -2
- package/dist/templates/vue2/icon.ts.vue.hbs +25 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -40,10 +40,10 @@ __export(helpers_exports, {
|
|
|
40
40
|
getComponentName: () => getComponentName,
|
|
41
41
|
getSvgFiles: () => getSvgFiles,
|
|
42
42
|
mergeClasses: () => mergeClasses,
|
|
43
|
-
readFile: () =>
|
|
43
|
+
readFile: () => readFile3,
|
|
44
44
|
toKebabCase: () => toKebabCase,
|
|
45
45
|
toPascalCase: () => toPascalCase,
|
|
46
|
-
writeFile: () =>
|
|
46
|
+
writeFile: () => writeFile2
|
|
47
47
|
});
|
|
48
48
|
function toPascalCase(str) {
|
|
49
49
|
return str.replace(/[-_](.)/g, (_, char) => char.toUpperCase()).replace(/^(.)/, (char) => char.toUpperCase()).replace(/[^a-z0-9]/gi, "");
|
|
@@ -93,11 +93,11 @@ async function fileExists(filePath) {
|
|
|
93
93
|
return false;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
async function
|
|
96
|
+
async function readFile3(filePath) {
|
|
97
97
|
const fs2 = await import("fs/promises");
|
|
98
98
|
return await fs2.readFile(filePath, "utf-8");
|
|
99
99
|
}
|
|
100
|
-
async function
|
|
100
|
+
async function writeFile2(filePath, content) {
|
|
101
101
|
const fs2 = await import("fs/promises");
|
|
102
102
|
await fs2.writeFile(filePath, content, "utf-8");
|
|
103
103
|
}
|
|
@@ -151,8 +151,288 @@ module.exports = __toCommonJS(src_exports);
|
|
|
151
151
|
var import_chalk = __toESM(require("chalk"));
|
|
152
152
|
var import_ora = __toESM(require("ora"));
|
|
153
153
|
|
|
154
|
+
// src/cache/cache-manager.ts
|
|
155
|
+
var import_node_fs = require("fs");
|
|
156
|
+
var import_promises2 = require("fs/promises");
|
|
157
|
+
var import_node_path = require("path");
|
|
158
|
+
|
|
159
|
+
// src/cache/hash-utils.ts
|
|
160
|
+
var import_node_crypto = require("crypto");
|
|
161
|
+
var import_promises = require("fs/promises");
|
|
162
|
+
function hashContent(content) {
|
|
163
|
+
return (0, import_node_crypto.createHash)("sha256").update(content).digest("hex");
|
|
164
|
+
}
|
|
165
|
+
async function hashFile(filePath) {
|
|
166
|
+
try {
|
|
167
|
+
const content = await (0, import_promises.readFile)(filePath, "utf-8");
|
|
168
|
+
return hashContent(content);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw new Error(`Failed to hash file ${filePath}: ${error}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function hashConfig(config) {
|
|
174
|
+
const relevantConfig = {
|
|
175
|
+
framework: config.framework,
|
|
176
|
+
typescript: config.typescript,
|
|
177
|
+
keepColors: config.keepColors,
|
|
178
|
+
prefix: config.prefix,
|
|
179
|
+
suffix: config.suffix,
|
|
180
|
+
optimize: config.optimize,
|
|
181
|
+
svgoConfig: config.svgoConfig,
|
|
182
|
+
componentNameTransform: config.componentNameTransform?.toString()
|
|
183
|
+
};
|
|
184
|
+
return hashContent(JSON.stringify(relevantConfig));
|
|
185
|
+
}
|
|
186
|
+
function hashSvgoConfig(svgoConfig) {
|
|
187
|
+
return hashContent(JSON.stringify(svgoConfig || {}));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/cache/cache-manager.ts
|
|
191
|
+
var CACHE_VERSION = "1.0.0";
|
|
192
|
+
var CacheManager = class {
|
|
193
|
+
constructor(outputDir, cacheDir = ".vectify") {
|
|
194
|
+
this.cache = {
|
|
195
|
+
version: CACHE_VERSION,
|
|
196
|
+
configHash: "",
|
|
197
|
+
entries: {},
|
|
198
|
+
baseComponentHash: ""
|
|
199
|
+
};
|
|
200
|
+
this.cacheFilePath = (0, import_node_path.join)(outputDir, cacheDir, "cache.json");
|
|
201
|
+
this.stats = {
|
|
202
|
+
hits: 0,
|
|
203
|
+
misses: 0,
|
|
204
|
+
total: 0,
|
|
205
|
+
timeSaved: 0
|
|
206
|
+
};
|
|
207
|
+
this.isDirty = false;
|
|
208
|
+
process.on("beforeExit", () => {
|
|
209
|
+
if (this.isDirty) {
|
|
210
|
+
this.saveSync();
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Load cache from disk
|
|
216
|
+
*/
|
|
217
|
+
async load() {
|
|
218
|
+
try {
|
|
219
|
+
if (!(0, import_node_fs.existsSync)(this.cacheFilePath)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const content = await (0, import_promises2.readFile)(this.cacheFilePath, "utf-8");
|
|
223
|
+
const loadedCache = JSON.parse(content);
|
|
224
|
+
if (loadedCache.version !== CACHE_VERSION) {
|
|
225
|
+
console.log("\u26A0\uFE0F Cache version mismatch, rebuilding cache...");
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
this.cache = loadedCache;
|
|
229
|
+
} catch (error) {
|
|
230
|
+
console.warn("\u26A0\uFE0F Failed to load cache, starting fresh:", error);
|
|
231
|
+
this.cache = {
|
|
232
|
+
version: CACHE_VERSION,
|
|
233
|
+
configHash: "",
|
|
234
|
+
entries: {},
|
|
235
|
+
baseComponentHash: ""
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Save cache to disk (atomic write)
|
|
241
|
+
*/
|
|
242
|
+
async save() {
|
|
243
|
+
try {
|
|
244
|
+
const cacheDir = (0, import_node_path.dirname)(this.cacheFilePath);
|
|
245
|
+
await (0, import_promises2.mkdir)(cacheDir, { recursive: true });
|
|
246
|
+
const tempPath = `${this.cacheFilePath}.tmp`;
|
|
247
|
+
await (0, import_promises2.writeFile)(tempPath, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
248
|
+
await (0, import_promises2.writeFile)(this.cacheFilePath, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
249
|
+
this.isDirty = false;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
console.warn("\u26A0\uFE0F Failed to save cache:", error);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Synchronous save for process exit
|
|
256
|
+
*/
|
|
257
|
+
saveSync() {
|
|
258
|
+
try {
|
|
259
|
+
const fs2 = require("fs");
|
|
260
|
+
const cacheDir = (0, import_node_path.dirname)(this.cacheFilePath);
|
|
261
|
+
if (!fs2.existsSync(cacheDir)) {
|
|
262
|
+
fs2.mkdirSync(cacheDir, { recursive: true });
|
|
263
|
+
}
|
|
264
|
+
fs2.writeFileSync(this.cacheFilePath, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
265
|
+
this.isDirty = false;
|
|
266
|
+
} catch {
|
|
267
|
+
console.warn("\u26A0\uFE0F Failed to save cache on exit");
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Check if a file needs regeneration
|
|
272
|
+
*/
|
|
273
|
+
async needsRegeneration(svgPath, componentPath, config) {
|
|
274
|
+
this.stats.total++;
|
|
275
|
+
if (!(0, import_node_fs.existsSync)(componentPath)) {
|
|
276
|
+
this.stats.misses++;
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
const entry = this.cache.entries[svgPath];
|
|
280
|
+
if (!entry) {
|
|
281
|
+
this.stats.misses++;
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const stats = await (0, import_promises2.stat)(svgPath);
|
|
286
|
+
const currentMtime = stats.mtimeMs;
|
|
287
|
+
if (currentMtime === entry.svgMtime) {
|
|
288
|
+
if (!this.isConfigMatching(entry, config)) {
|
|
289
|
+
this.stats.misses++;
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
this.stats.hits++;
|
|
293
|
+
this.stats.timeSaved += 50;
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
const currentHash = await hashFile(svgPath);
|
|
297
|
+
if (currentHash === entry.svgHash) {
|
|
298
|
+
entry.svgMtime = currentMtime;
|
|
299
|
+
this.isDirty = true;
|
|
300
|
+
this.stats.hits++;
|
|
301
|
+
this.stats.timeSaved += 50;
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
this.stats.misses++;
|
|
305
|
+
return true;
|
|
306
|
+
} catch {
|
|
307
|
+
this.stats.misses++;
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Check if config matches cache entry
|
|
313
|
+
*/
|
|
314
|
+
isConfigMatching(entry, config) {
|
|
315
|
+
const snapshot = entry.configSnapshot;
|
|
316
|
+
return snapshot.framework === config.framework && snapshot.typescript === config.typescript && snapshot.keepColors === config.keepColors && snapshot.prefix === (config.prefix || "") && snapshot.suffix === (config.suffix || "") && snapshot.optimize === config.optimize && snapshot.svgoConfigHash === hashSvgoConfig(config.svgoConfig);
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Update cache entry after successful generation
|
|
320
|
+
*/
|
|
321
|
+
async updateEntry(svgPath, componentPath, componentName, componentHash, config) {
|
|
322
|
+
try {
|
|
323
|
+
const svgHash = await hashFile(svgPath);
|
|
324
|
+
const stats = await (0, import_promises2.stat)(svgPath);
|
|
325
|
+
this.cache.entries[svgPath] = {
|
|
326
|
+
svgPath,
|
|
327
|
+
svgHash,
|
|
328
|
+
svgMtime: stats.mtimeMs,
|
|
329
|
+
componentName,
|
|
330
|
+
componentPath,
|
|
331
|
+
componentHash,
|
|
332
|
+
configSnapshot: {
|
|
333
|
+
framework: config.framework,
|
|
334
|
+
typescript: config.typescript ?? true,
|
|
335
|
+
keepColors: config.keepColors ?? false,
|
|
336
|
+
prefix: config.prefix || "",
|
|
337
|
+
suffix: config.suffix || "",
|
|
338
|
+
optimize: config.optimize ?? true,
|
|
339
|
+
svgoConfigHash: hashSvgoConfig(config.svgoConfig)
|
|
340
|
+
},
|
|
341
|
+
generatedAt: Date.now()
|
|
342
|
+
};
|
|
343
|
+
this.isDirty = true;
|
|
344
|
+
} catch (error) {
|
|
345
|
+
console.warn(`\u26A0\uFE0F Failed to update cache entry for ${svgPath}:`, error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Remove cache entry
|
|
350
|
+
*/
|
|
351
|
+
removeEntry(svgPath) {
|
|
352
|
+
if (this.cache.entries[svgPath]) {
|
|
353
|
+
delete this.cache.entries[svgPath];
|
|
354
|
+
this.isDirty = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Update config hash
|
|
359
|
+
*/
|
|
360
|
+
updateConfigHash(config) {
|
|
361
|
+
const newHash = hashConfig(config);
|
|
362
|
+
if (this.cache.configHash !== newHash) {
|
|
363
|
+
this.cache.configHash = newHash;
|
|
364
|
+
this.isDirty = true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Update base component hash
|
|
369
|
+
*/
|
|
370
|
+
updateBaseComponentHash(hash) {
|
|
371
|
+
if (this.cache.baseComponentHash !== hash) {
|
|
372
|
+
this.cache.baseComponentHash = hash;
|
|
373
|
+
this.isDirty = true;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Check if config has changed (invalidates all cache)
|
|
378
|
+
*/
|
|
379
|
+
hasConfigChanged(config) {
|
|
380
|
+
const currentHash = hashConfig(config);
|
|
381
|
+
return this.cache.configHash !== "" && this.cache.configHash !== currentHash;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Invalidate all cache entries
|
|
385
|
+
*/
|
|
386
|
+
invalidateAll() {
|
|
387
|
+
this.cache.entries = {};
|
|
388
|
+
this.isDirty = true;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Clean stale entries (files that no longer exist)
|
|
392
|
+
*/
|
|
393
|
+
async cleanStaleEntries(existingSvgPaths) {
|
|
394
|
+
const existingSet = new Set(existingSvgPaths);
|
|
395
|
+
let cleaned = 0;
|
|
396
|
+
for (const svgPath of Object.keys(this.cache.entries)) {
|
|
397
|
+
if (!existingSet.has(svgPath)) {
|
|
398
|
+
delete this.cache.entries[svgPath];
|
|
399
|
+
cleaned++;
|
|
400
|
+
this.isDirty = true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (cleaned > 0) {
|
|
404
|
+
console.log(`\u{1F9F9} Cleaned ${cleaned} stale cache entries`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get cache statistics
|
|
409
|
+
*/
|
|
410
|
+
getStats() {
|
|
411
|
+
return { ...this.stats };
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Reset statistics
|
|
415
|
+
*/
|
|
416
|
+
resetStats() {
|
|
417
|
+
this.stats = {
|
|
418
|
+
hits: 0,
|
|
419
|
+
misses: 0,
|
|
420
|
+
total: 0,
|
|
421
|
+
timeSaved: 0
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Get cache hit rate
|
|
426
|
+
*/
|
|
427
|
+
getHitRate() {
|
|
428
|
+
if (this.stats.total === 0)
|
|
429
|
+
return 0;
|
|
430
|
+
return this.stats.hits / this.stats.total * 100;
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
|
|
154
434
|
// src/config/loader.ts
|
|
155
|
-
var
|
|
435
|
+
var import_node_path3 = __toESM(require("path"));
|
|
156
436
|
var import_node_process = __toESM(require("process"));
|
|
157
437
|
var import_jiti = require("jiti");
|
|
158
438
|
|
|
@@ -176,6 +456,7 @@ function parseSvg(svgContent) {
|
|
|
176
456
|
if (svgElement.length === 0) {
|
|
177
457
|
throw new Error("Invalid SVG: No <svg> tag found");
|
|
178
458
|
}
|
|
459
|
+
const viewBox = svgElement.attr("viewBox") || "0 0 24 24";
|
|
179
460
|
const iconNodes = [];
|
|
180
461
|
svgElement.children().each((_, element) => {
|
|
181
462
|
const node = parseElement($, element);
|
|
@@ -183,7 +464,29 @@ function parseSvg(svgContent) {
|
|
|
183
464
|
iconNodes.push(node);
|
|
184
465
|
}
|
|
185
466
|
});
|
|
186
|
-
|
|
467
|
+
const isMultiColor = detectMultiColor(iconNodes);
|
|
468
|
+
return { iconNodes, viewBox, isMultiColor };
|
|
469
|
+
}
|
|
470
|
+
function detectMultiColor(nodes) {
|
|
471
|
+
const colors = /* @__PURE__ */ new Set();
|
|
472
|
+
function collectColors(node) {
|
|
473
|
+
const [, attrs, children] = node;
|
|
474
|
+
if (attrs.fill && attrs.fill !== "none" && attrs.fill !== "transparent") {
|
|
475
|
+
colors.add(String(attrs.fill).toLowerCase());
|
|
476
|
+
}
|
|
477
|
+
if (attrs.stroke && attrs.stroke !== "none" && attrs.stroke !== "transparent") {
|
|
478
|
+
colors.add(String(attrs.stroke).toLowerCase());
|
|
479
|
+
}
|
|
480
|
+
if (children && children.length > 0) {
|
|
481
|
+
children.forEach(collectColors);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
nodes.forEach(collectColors);
|
|
485
|
+
const realColors = Array.from(colors).filter((color) => {
|
|
486
|
+
const c = color.toLowerCase();
|
|
487
|
+
return c !== "currentcolor";
|
|
488
|
+
});
|
|
489
|
+
return realColors.length >= 2;
|
|
187
490
|
}
|
|
188
491
|
function parseElement($, element) {
|
|
189
492
|
if (element.type !== "tag") {
|
|
@@ -254,22 +557,22 @@ function formatAttrs(attrs) {
|
|
|
254
557
|
}
|
|
255
558
|
|
|
256
559
|
// src/generators/templates/template-engine.ts
|
|
257
|
-
var
|
|
258
|
-
var
|
|
560
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
561
|
+
var import_node_path2 = __toESM(require("path"));
|
|
259
562
|
var import_node_url = require("url");
|
|
260
563
|
var import_handlebars = __toESM(require("handlebars"));
|
|
261
564
|
var import_meta = {};
|
|
262
565
|
function getTemplatesDir() {
|
|
263
566
|
if (typeof __dirname !== "undefined") {
|
|
264
|
-
return
|
|
567
|
+
return import_node_path2.default.join(__dirname, "templates");
|
|
265
568
|
}
|
|
266
569
|
const currentFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
267
|
-
return
|
|
570
|
+
return import_node_path2.default.join(import_node_path2.default.dirname(currentFile), "templates");
|
|
268
571
|
}
|
|
269
572
|
function loadTemplate(templatePath) {
|
|
270
573
|
const templatesDir = getTemplatesDir();
|
|
271
|
-
const fullPath =
|
|
272
|
-
const templateContent =
|
|
574
|
+
const fullPath = import_node_path2.default.join(templatesDir, templatePath);
|
|
575
|
+
const templateContent = import_node_fs2.default.readFileSync(fullPath, "utf-8");
|
|
273
576
|
return import_handlebars.default.compile(templateContent, { noEscape: true });
|
|
274
577
|
}
|
|
275
578
|
function renderTemplate(templatePath, data) {
|
|
@@ -313,14 +616,15 @@ function getQwikTemplatePath(typescript, type) {
|
|
|
313
616
|
function getAngularTemplatePath(type) {
|
|
314
617
|
return `angular/${type}.ts.hbs`;
|
|
315
618
|
}
|
|
316
|
-
function generateAngularComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
619
|
+
function generateAngularComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
317
620
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
318
621
|
const templatePath = getAngularTemplatePath("component");
|
|
319
622
|
return renderTemplate(templatePath, {
|
|
320
623
|
componentName,
|
|
321
624
|
formattedNodes,
|
|
322
625
|
typescript,
|
|
323
|
-
keepColors
|
|
626
|
+
keepColors,
|
|
627
|
+
viewBox
|
|
324
628
|
});
|
|
325
629
|
}
|
|
326
630
|
function generateAngularBaseComponent(typescript) {
|
|
@@ -335,14 +639,15 @@ function generateAngularBaseComponent(typescript) {
|
|
|
335
639
|
function getAstroTemplatePath(type) {
|
|
336
640
|
return `astro/${type}.astro.hbs`;
|
|
337
641
|
}
|
|
338
|
-
function generateAstroComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
642
|
+
function generateAstroComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
339
643
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
340
644
|
const templatePath = getAstroTemplatePath("component");
|
|
341
645
|
return renderTemplate(templatePath, {
|
|
342
646
|
componentName,
|
|
343
647
|
formattedNodes,
|
|
344
648
|
typescript,
|
|
345
|
-
keepColors
|
|
649
|
+
keepColors,
|
|
650
|
+
viewBox
|
|
346
651
|
});
|
|
347
652
|
}
|
|
348
653
|
function generateAstroBaseComponent(typescript) {
|
|
@@ -358,14 +663,15 @@ function getLitTemplatePath(typescript, type) {
|
|
|
358
663
|
const ext = typescript ? "ts" : "js";
|
|
359
664
|
return `lit/${type}.${ext}.hbs`;
|
|
360
665
|
}
|
|
361
|
-
function generateLitComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
666
|
+
function generateLitComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
362
667
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
363
668
|
const templatePath = getLitTemplatePath(typescript, "component");
|
|
364
669
|
return renderTemplate(templatePath, {
|
|
365
670
|
componentName,
|
|
366
671
|
formattedNodes,
|
|
367
672
|
typescript,
|
|
368
|
-
keepColors
|
|
673
|
+
keepColors,
|
|
674
|
+
viewBox
|
|
369
675
|
});
|
|
370
676
|
}
|
|
371
677
|
function generateLitBaseComponent(typescript) {
|
|
@@ -377,14 +683,15 @@ function generateLitBaseComponent(typescript) {
|
|
|
377
683
|
}
|
|
378
684
|
|
|
379
685
|
// src/generators/react.ts
|
|
380
|
-
function generateReactComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
686
|
+
function generateReactComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
381
687
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
382
688
|
const templatePath = getReactTemplatePath(typescript, "component");
|
|
383
689
|
return renderTemplate(templatePath, {
|
|
384
690
|
typescript,
|
|
385
691
|
componentName,
|
|
386
692
|
formattedNodes,
|
|
387
|
-
keepColors
|
|
693
|
+
keepColors,
|
|
694
|
+
viewBox
|
|
388
695
|
});
|
|
389
696
|
}
|
|
390
697
|
function generateCreateIcon(typescript) {
|
|
@@ -393,7 +700,7 @@ function generateCreateIcon(typescript) {
|
|
|
393
700
|
}
|
|
394
701
|
|
|
395
702
|
// src/generators/react-like.ts
|
|
396
|
-
function generateReactLikeComponent(componentName, iconNode, typescript, keepColors, framework) {
|
|
703
|
+
function generateReactLikeComponent(componentName, iconNode, typescript, keepColors, viewBox, framework) {
|
|
397
704
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
398
705
|
let templatePath;
|
|
399
706
|
if (framework === "solid") {
|
|
@@ -409,7 +716,8 @@ function generateReactLikeComponent(componentName, iconNode, typescript, keepCol
|
|
|
409
716
|
componentName,
|
|
410
717
|
formattedNodes,
|
|
411
718
|
typescript,
|
|
412
|
-
keepColors
|
|
719
|
+
keepColors,
|
|
720
|
+
viewBox
|
|
413
721
|
});
|
|
414
722
|
}
|
|
415
723
|
function generateReactLikeBaseComponent(typescript, framework) {
|
|
@@ -430,12 +738,14 @@ function generateReactLikeBaseComponent(typescript, framework) {
|
|
|
430
738
|
}
|
|
431
739
|
|
|
432
740
|
// src/generators/svelte.ts
|
|
433
|
-
function generateSvelteComponent(_componentName, iconNode, typescript) {
|
|
741
|
+
function generateSvelteComponent(_componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
434
742
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
435
743
|
const templatePath = getSvelteTemplatePath(typescript, "component");
|
|
436
744
|
return renderTemplate(templatePath, {
|
|
437
745
|
typescript,
|
|
438
|
-
formattedNodes
|
|
746
|
+
formattedNodes,
|
|
747
|
+
keepColors,
|
|
748
|
+
viewBox
|
|
439
749
|
});
|
|
440
750
|
}
|
|
441
751
|
function generateSvelteIcon(typescript) {
|
|
@@ -444,14 +754,15 @@ function generateSvelteIcon(typescript) {
|
|
|
444
754
|
}
|
|
445
755
|
|
|
446
756
|
// src/generators/vanilla.ts
|
|
447
|
-
function generateVanillaComponent(componentName, iconNode, typescript, keepColors) {
|
|
757
|
+
function generateVanillaComponent(componentName, iconNode, typescript, keepColors, viewBox) {
|
|
448
758
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
449
759
|
const templatePath = getVanillaTemplatePath(typescript, "component");
|
|
450
760
|
return renderTemplate(templatePath, {
|
|
451
761
|
componentName,
|
|
452
762
|
formattedNodes,
|
|
453
763
|
typescript,
|
|
454
|
-
keepColors
|
|
764
|
+
keepColors,
|
|
765
|
+
viewBox
|
|
455
766
|
});
|
|
456
767
|
}
|
|
457
768
|
function generateVanillaBaseComponent(typescript) {
|
|
@@ -463,13 +774,15 @@ function generateVanillaBaseComponent(typescript) {
|
|
|
463
774
|
}
|
|
464
775
|
|
|
465
776
|
// src/generators/vue.ts
|
|
466
|
-
function generateVueComponent(componentName, iconNode, typescript) {
|
|
777
|
+
function generateVueComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
467
778
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
468
779
|
const templatePath = getVueTemplatePath(typescript, "component");
|
|
469
780
|
return renderTemplate(templatePath, {
|
|
470
781
|
typescript,
|
|
471
782
|
componentName,
|
|
472
|
-
formattedNodes
|
|
783
|
+
formattedNodes,
|
|
784
|
+
keepColors,
|
|
785
|
+
viewBox
|
|
473
786
|
});
|
|
474
787
|
}
|
|
475
788
|
function generateVueIcon(typescript) {
|
|
@@ -478,13 +791,15 @@ function generateVueIcon(typescript) {
|
|
|
478
791
|
}
|
|
479
792
|
|
|
480
793
|
// src/generators/vue2.ts
|
|
481
|
-
function generateVue2Component(componentName, iconNode, typescript) {
|
|
794
|
+
function generateVue2Component(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
482
795
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
483
796
|
const templatePath = getVue2TemplatePath(typescript, "component");
|
|
484
797
|
return renderTemplate(templatePath, {
|
|
485
798
|
typescript,
|
|
486
799
|
componentName,
|
|
487
|
-
formattedNodes
|
|
800
|
+
formattedNodes,
|
|
801
|
+
keepColors,
|
|
802
|
+
viewBox
|
|
488
803
|
});
|
|
489
804
|
}
|
|
490
805
|
function generateVue2Icon(typescript) {
|
|
@@ -502,8 +817,8 @@ var ReactStrategy = class {
|
|
|
502
817
|
this.getIndexExtension = (typescript) => {
|
|
503
818
|
return typescript ? "ts" : "js";
|
|
504
819
|
};
|
|
505
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors = false) => {
|
|
506
|
-
return generateReactComponent(componentName, iconNode, typescript, keepColors);
|
|
820
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
821
|
+
return generateReactComponent(componentName, iconNode, typescript, keepColors, viewBox);
|
|
507
822
|
};
|
|
508
823
|
this.generateBaseComponent = (typescript) => {
|
|
509
824
|
return {
|
|
@@ -522,8 +837,8 @@ var VueStrategy = class {
|
|
|
522
837
|
this.getIndexExtension = (typescript) => {
|
|
523
838
|
return typescript ? "ts" : "js";
|
|
524
839
|
};
|
|
525
|
-
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
526
|
-
return generateVueComponent(componentName, iconNode, typescript);
|
|
840
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
841
|
+
return generateVueComponent(componentName, iconNode, typescript, keepColors, viewBox);
|
|
527
842
|
};
|
|
528
843
|
this.generateBaseComponent = (typescript) => {
|
|
529
844
|
return {
|
|
@@ -542,8 +857,8 @@ var Vue2Strategy = class {
|
|
|
542
857
|
this.getIndexExtension = (typescript) => {
|
|
543
858
|
return typescript ? "ts" : "js";
|
|
544
859
|
};
|
|
545
|
-
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
546
|
-
return generateVue2Component(componentName, iconNode, typescript);
|
|
860
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
861
|
+
return generateVue2Component(componentName, iconNode, typescript, keepColors, viewBox);
|
|
547
862
|
};
|
|
548
863
|
this.generateBaseComponent = (typescript) => {
|
|
549
864
|
return {
|
|
@@ -562,8 +877,8 @@ var SvelteStrategy = class {
|
|
|
562
877
|
this.getIndexExtension = (typescript) => {
|
|
563
878
|
return typescript ? "ts" : "js";
|
|
564
879
|
};
|
|
565
|
-
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
566
|
-
return generateSvelteComponent(componentName, iconNode, typescript);
|
|
880
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
881
|
+
return generateSvelteComponent(componentName, iconNode, typescript, keepColors, viewBox);
|
|
567
882
|
};
|
|
568
883
|
this.generateBaseComponent = (typescript) => {
|
|
569
884
|
return {
|
|
@@ -582,8 +897,8 @@ var SolidStrategy = class {
|
|
|
582
897
|
this.getIndexExtension = (typescript) => {
|
|
583
898
|
return typescript ? "ts" : "js";
|
|
584
899
|
};
|
|
585
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
586
|
-
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "solid");
|
|
900
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
901
|
+
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24", "solid");
|
|
587
902
|
};
|
|
588
903
|
this.generateBaseComponent = (typescript) => {
|
|
589
904
|
return generateReactLikeBaseComponent(typescript, "solid");
|
|
@@ -599,8 +914,8 @@ var PreactStrategy = class {
|
|
|
599
914
|
this.getIndexExtension = (typescript) => {
|
|
600
915
|
return typescript ? "ts" : "js";
|
|
601
916
|
};
|
|
602
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
603
|
-
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "preact");
|
|
917
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
918
|
+
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24", "preact");
|
|
604
919
|
};
|
|
605
920
|
this.generateBaseComponent = (typescript) => {
|
|
606
921
|
return generateReactLikeBaseComponent(typescript, "preact");
|
|
@@ -616,8 +931,8 @@ var VanillaStrategy = class {
|
|
|
616
931
|
this.getIndexExtension = (typescript) => {
|
|
617
932
|
return typescript ? "ts" : "js";
|
|
618
933
|
};
|
|
619
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
620
|
-
return generateVanillaComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
934
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
935
|
+
return generateVanillaComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
621
936
|
};
|
|
622
937
|
this.generateBaseComponent = (typescript) => {
|
|
623
938
|
return generateVanillaBaseComponent(typescript);
|
|
@@ -633,8 +948,8 @@ var LitStrategy = class {
|
|
|
633
948
|
this.getIndexExtension = (typescript) => {
|
|
634
949
|
return typescript ? "ts" : "js";
|
|
635
950
|
};
|
|
636
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
637
|
-
return generateLitComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
951
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
952
|
+
return generateLitComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
638
953
|
};
|
|
639
954
|
this.generateBaseComponent = (typescript) => {
|
|
640
955
|
return generateLitBaseComponent(typescript);
|
|
@@ -650,8 +965,8 @@ var QwikStrategy = class {
|
|
|
650
965
|
this.getIndexExtension = (typescript) => {
|
|
651
966
|
return typescript ? "ts" : "js";
|
|
652
967
|
};
|
|
653
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
654
|
-
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "qwik");
|
|
968
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
969
|
+
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24", "qwik");
|
|
655
970
|
};
|
|
656
971
|
this.generateBaseComponent = (typescript) => {
|
|
657
972
|
return generateReactLikeBaseComponent(typescript, "qwik");
|
|
@@ -667,8 +982,8 @@ var AstroStrategy = class {
|
|
|
667
982
|
this.getIndexExtension = (typescript) => {
|
|
668
983
|
return typescript ? "ts" : "js";
|
|
669
984
|
};
|
|
670
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
671
|
-
return generateAstroComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
985
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
986
|
+
return generateAstroComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
672
987
|
};
|
|
673
988
|
this.generateBaseComponent = (typescript) => {
|
|
674
989
|
return generateAstroBaseComponent(typescript);
|
|
@@ -684,8 +999,8 @@ var AngularStrategy = class {
|
|
|
684
999
|
this.getIndexExtension = (_typescript) => {
|
|
685
1000
|
return "ts";
|
|
686
1001
|
};
|
|
687
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
688
|
-
return generateAngularComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
1002
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
1003
|
+
return generateAngularComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
689
1004
|
};
|
|
690
1005
|
this.generateBaseComponent = (typescript) => {
|
|
691
1006
|
return generateAngularBaseComponent(typescript);
|
|
@@ -747,7 +1062,6 @@ var DEFAULT_CONFIG = {
|
|
|
747
1062
|
output: "./src/icons",
|
|
748
1063
|
typescript: true,
|
|
749
1064
|
optimize: true,
|
|
750
|
-
keepColors: false,
|
|
751
1065
|
prefix: "",
|
|
752
1066
|
suffix: "",
|
|
753
1067
|
configDir: ".",
|
|
@@ -764,8 +1078,8 @@ var DEFAULT_CONFIG = {
|
|
|
764
1078
|
}
|
|
765
1079
|
};
|
|
766
1080
|
async function loadConfig(configPath) {
|
|
767
|
-
const absolutePath =
|
|
768
|
-
const configDir =
|
|
1081
|
+
const absolutePath = import_node_path3.default.resolve(import_node_process.default.cwd(), configPath);
|
|
1082
|
+
const configDir = import_node_path3.default.dirname(absolutePath);
|
|
769
1083
|
const jiti = (0, import_jiti.createJiti)(configDir, {
|
|
770
1084
|
interopDefault: true
|
|
771
1085
|
});
|
|
@@ -792,12 +1106,12 @@ async function loadConfig(configPath) {
|
|
|
792
1106
|
}
|
|
793
1107
|
};
|
|
794
1108
|
if (mergedConfig.configDir && mergedConfig.configDir !== ".") {
|
|
795
|
-
const projectRoot =
|
|
796
|
-
mergedConfig.input =
|
|
797
|
-
mergedConfig.output =
|
|
1109
|
+
const projectRoot = import_node_path3.default.resolve(configDir, mergedConfig.configDir);
|
|
1110
|
+
mergedConfig.input = import_node_path3.default.resolve(projectRoot, mergedConfig.input);
|
|
1111
|
+
mergedConfig.output = import_node_path3.default.resolve(projectRoot, mergedConfig.output);
|
|
798
1112
|
} else {
|
|
799
|
-
mergedConfig.input =
|
|
800
|
-
mergedConfig.output =
|
|
1113
|
+
mergedConfig.input = import_node_path3.default.resolve(configDir, mergedConfig.input);
|
|
1114
|
+
mergedConfig.output = import_node_path3.default.resolve(configDir, mergedConfig.output);
|
|
801
1115
|
}
|
|
802
1116
|
if (!mergedConfig.framework) {
|
|
803
1117
|
const supported = frameworkRegistry.getSupportedFrameworks().join(", ");
|
|
@@ -816,7 +1130,7 @@ async function findConfig() {
|
|
|
816
1130
|
"vectify.config.js"
|
|
817
1131
|
];
|
|
818
1132
|
for (const file of configFiles) {
|
|
819
|
-
const configPath =
|
|
1133
|
+
const configPath = import_node_path3.default.resolve(import_node_process.default.cwd(), file);
|
|
820
1134
|
if (await fileExists2(configPath)) {
|
|
821
1135
|
return configPath;
|
|
822
1136
|
}
|
|
@@ -825,7 +1139,7 @@ async function findConfig() {
|
|
|
825
1139
|
}
|
|
826
1140
|
|
|
827
1141
|
// src/generators/index.ts
|
|
828
|
-
var
|
|
1142
|
+
var import_node_path5 = __toESM(require("path"));
|
|
829
1143
|
|
|
830
1144
|
// src/parsers/optimizer.ts
|
|
831
1145
|
var import_svgo = require("svgo");
|
|
@@ -861,7 +1175,7 @@ async function optimizeSvg(svgContent, config) {
|
|
|
861
1175
|
|
|
862
1176
|
// src/utils/formatter.ts
|
|
863
1177
|
var import_node_child_process = require("child_process");
|
|
864
|
-
var
|
|
1178
|
+
var import_node_path4 = __toESM(require("path"));
|
|
865
1179
|
var import_node_process2 = __toESM(require("process"));
|
|
866
1180
|
var import_node_util = require("util");
|
|
867
1181
|
init_helpers();
|
|
@@ -916,7 +1230,7 @@ async function detectFormatter() {
|
|
|
916
1230
|
for (const tool of priority) {
|
|
917
1231
|
const patterns = FORMATTER_PATTERNS[tool];
|
|
918
1232
|
for (const pattern of patterns) {
|
|
919
|
-
const configPath =
|
|
1233
|
+
const configPath = import_node_path4.default.join(cwd, pattern);
|
|
920
1234
|
if (await fileExists(configPath)) {
|
|
921
1235
|
return tool;
|
|
922
1236
|
}
|
|
@@ -1012,90 +1326,206 @@ async function generateIcons(config, dryRun = false) {
|
|
|
1012
1326
|
}
|
|
1013
1327
|
return stats;
|
|
1014
1328
|
}
|
|
1015
|
-
async function
|
|
1016
|
-
|
|
1017
|
-
|
|
1329
|
+
async function generateIconsIncremental(config, cacheManager, dryRun = false) {
|
|
1330
|
+
const stats = {
|
|
1331
|
+
success: 0,
|
|
1332
|
+
failed: 0,
|
|
1333
|
+
total: 0,
|
|
1334
|
+
errors: []
|
|
1335
|
+
};
|
|
1336
|
+
try {
|
|
1337
|
+
if (!dryRun) {
|
|
1338
|
+
await ensureDir(config.output);
|
|
1339
|
+
}
|
|
1340
|
+
const svgFiles = await getSvgFiles(config.input);
|
|
1341
|
+
stats.total = svgFiles.length;
|
|
1342
|
+
if (svgFiles.length === 0) {
|
|
1343
|
+
console.warn(`No SVG files found in ${config.input}`);
|
|
1344
|
+
return stats;
|
|
1345
|
+
}
|
|
1346
|
+
if (cacheManager.hasConfigChanged(config)) {
|
|
1347
|
+
console.log("\u26A0\uFE0F Configuration changed, rebuilding all icons...");
|
|
1348
|
+
cacheManager.invalidateAll();
|
|
1349
|
+
}
|
|
1350
|
+
cacheManager.updateConfigHash(config);
|
|
1351
|
+
await cacheManager.cleanStaleEntries(svgFiles);
|
|
1352
|
+
if (config.generateOptions?.cleanOutput && !dryRun) {
|
|
1353
|
+
await cleanOutputDirectory(svgFiles, config);
|
|
1354
|
+
}
|
|
1355
|
+
await generateBaseComponent(config, dryRun);
|
|
1356
|
+
const strategy = getFrameworkStrategy(config.framework);
|
|
1357
|
+
const typescript = config.typescript ?? true;
|
|
1358
|
+
const fileExt = strategy.getComponentExtension(typescript);
|
|
1359
|
+
const filesToGenerate = [];
|
|
1360
|
+
const cachedFiles = [];
|
|
1361
|
+
for (const svgFile of svgFiles) {
|
|
1362
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1363
|
+
const componentName = getComponentName(
|
|
1364
|
+
fileName,
|
|
1365
|
+
config.prefix,
|
|
1366
|
+
config.suffix,
|
|
1367
|
+
config.componentNameTransform
|
|
1368
|
+
);
|
|
1369
|
+
const componentPath = import_node_path5.default.join(config.output, `${componentName}.${fileExt}`);
|
|
1370
|
+
const needsRegen = await cacheManager.needsRegeneration(
|
|
1371
|
+
svgFile,
|
|
1372
|
+
componentPath,
|
|
1373
|
+
config
|
|
1374
|
+
);
|
|
1375
|
+
if (needsRegen) {
|
|
1376
|
+
filesToGenerate.push(svgFile);
|
|
1377
|
+
} else {
|
|
1378
|
+
cachedFiles.push(svgFile);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
if (cachedFiles.length > 0) {
|
|
1382
|
+
console.log(`\u{1F4E6} Cache: ${cachedFiles.length} cached, ${filesToGenerate.length} to generate`);
|
|
1383
|
+
}
|
|
1384
|
+
for (const svgFile of filesToGenerate) {
|
|
1385
|
+
try {
|
|
1386
|
+
await generateIconComponent(svgFile, config, dryRun, cacheManager);
|
|
1387
|
+
stats.success++;
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
stats.failed++;
|
|
1390
|
+
stats.errors.push({
|
|
1391
|
+
file: svgFile,
|
|
1392
|
+
error: error.message
|
|
1393
|
+
});
|
|
1394
|
+
console.error(`Failed to generate ${svgFile}: ${error.message}`);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
stats.success += cachedFiles.length;
|
|
1398
|
+
if (config.generateOptions?.index) {
|
|
1399
|
+
await generateIndexFile(svgFiles, config, dryRun);
|
|
1400
|
+
}
|
|
1401
|
+
if (config.generateOptions?.preview && !dryRun) {
|
|
1402
|
+
await generatePreviewHtml(svgFiles, config);
|
|
1403
|
+
}
|
|
1404
|
+
if (!dryRun) {
|
|
1405
|
+
await cacheManager.save();
|
|
1406
|
+
const cacheStats = cacheManager.getStats();
|
|
1407
|
+
if (cacheStats.total > 0) {
|
|
1408
|
+
const hitRate = cacheManager.getHitRate();
|
|
1409
|
+
const timeSaved = (cacheStats.timeSaved / 1e3).toFixed(1);
|
|
1410
|
+
console.log(`\u26A1 Cache saved ~${timeSaved}s (${hitRate.toFixed(1)}% hit rate)`);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
if (config.format && !dryRun) {
|
|
1414
|
+
const formatResult = await formatOutput(config.output, config.format);
|
|
1415
|
+
if (formatResult.success && formatResult.tool) {
|
|
1416
|
+
console.log(`Formatted with ${formatResult.tool}`);
|
|
1417
|
+
} else if (formatResult.error) {
|
|
1418
|
+
console.warn(formatResult.error);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
if (config.hooks?.onComplete) {
|
|
1422
|
+
await config.hooks.onComplete(stats);
|
|
1423
|
+
}
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
throw new Error(`Generation failed: ${error.message}`);
|
|
1426
|
+
}
|
|
1427
|
+
return stats;
|
|
1428
|
+
}
|
|
1429
|
+
async function generateIconComponent(svgFile, config, dryRun = false, cacheManager) {
|
|
1430
|
+
let svgContent = await readFile3(svgFile);
|
|
1431
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1018
1432
|
if (config.hooks?.beforeParse) {
|
|
1019
1433
|
svgContent = await config.hooks.beforeParse(svgContent, fileName);
|
|
1020
1434
|
}
|
|
1435
|
+
const { isMultiColor: isMultiColorBeforeOptimization } = parseSvg(svgContent);
|
|
1021
1436
|
svgContent = await optimizeSvg(svgContent, config);
|
|
1022
|
-
const
|
|
1437
|
+
const { iconNodes, viewBox } = parseSvg(svgContent);
|
|
1023
1438
|
const componentName = getComponentName(
|
|
1024
1439
|
fileName,
|
|
1025
1440
|
config.prefix,
|
|
1026
1441
|
config.suffix,
|
|
1027
|
-
config.
|
|
1442
|
+
config.componentNameTransform
|
|
1028
1443
|
);
|
|
1029
1444
|
const strategy = getFrameworkStrategy(config.framework);
|
|
1030
1445
|
const typescript = config.typescript ?? true;
|
|
1446
|
+
const keepColors = config.keepColors !== void 0 ? config.keepColors : isMultiColorBeforeOptimization;
|
|
1031
1447
|
let code = strategy.generateComponent(
|
|
1032
1448
|
componentName,
|
|
1033
|
-
|
|
1449
|
+
iconNodes,
|
|
1034
1450
|
typescript,
|
|
1035
|
-
|
|
1451
|
+
keepColors,
|
|
1452
|
+
viewBox
|
|
1036
1453
|
);
|
|
1037
1454
|
if (config.hooks?.afterGenerate) {
|
|
1038
1455
|
code = await config.hooks.afterGenerate(code, componentName);
|
|
1039
1456
|
}
|
|
1040
1457
|
const fileExt = strategy.getComponentExtension(typescript);
|
|
1041
|
-
const outputPath =
|
|
1458
|
+
const outputPath = import_node_path5.default.join(config.output, `${componentName}.${fileExt}`);
|
|
1042
1459
|
if (dryRun) {
|
|
1043
1460
|
console.log(` ${componentName}.${fileExt}`);
|
|
1044
1461
|
} else {
|
|
1045
|
-
await
|
|
1462
|
+
await writeFile2(outputPath, code);
|
|
1463
|
+
if (cacheManager) {
|
|
1464
|
+
const componentHash = hashContent(code);
|
|
1465
|
+
await cacheManager.updateEntry(
|
|
1466
|
+
svgFile,
|
|
1467
|
+
outputPath,
|
|
1468
|
+
componentName,
|
|
1469
|
+
componentHash,
|
|
1470
|
+
config
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1046
1473
|
}
|
|
1047
1474
|
}
|
|
1048
1475
|
async function generateBaseComponent(config, dryRun = false) {
|
|
1049
1476
|
const typescript = config.typescript ?? true;
|
|
1050
1477
|
const strategy = getFrameworkStrategy(config.framework);
|
|
1051
1478
|
const { code, fileName } = strategy.generateBaseComponent(typescript);
|
|
1052
|
-
const outputPath =
|
|
1479
|
+
const outputPath = import_node_path5.default.join(config.output, fileName);
|
|
1053
1480
|
if (dryRun) {
|
|
1054
1481
|
console.log(` ${fileName}`);
|
|
1055
1482
|
} else {
|
|
1056
|
-
await
|
|
1483
|
+
await writeFile2(outputPath, code);
|
|
1057
1484
|
}
|
|
1058
1485
|
}
|
|
1059
1486
|
async function generateIndexFile(svgFiles, config, dryRun = false) {
|
|
1060
1487
|
const typescript = config.typescript ?? true;
|
|
1061
1488
|
const strategy = getFrameworkStrategy(config.framework);
|
|
1062
1489
|
const ext = strategy.getIndexExtension(typescript);
|
|
1490
|
+
const componentExt = strategy.getComponentExtension(typescript);
|
|
1063
1491
|
const usesDefaultExport = ["vue", "vue2", "svelte", "react", "preact"].includes(config.framework);
|
|
1492
|
+
const needsExtension = ["vue", "vue2", "svelte"].includes(config.framework);
|
|
1064
1493
|
const exports2 = svgFiles.map((svgFile) => {
|
|
1065
|
-
const fileName =
|
|
1494
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1066
1495
|
const componentName = getComponentName(
|
|
1067
1496
|
fileName,
|
|
1068
1497
|
config.prefix,
|
|
1069
1498
|
config.suffix,
|
|
1070
|
-
config.
|
|
1499
|
+
config.componentNameTransform
|
|
1071
1500
|
);
|
|
1501
|
+
const importPath = needsExtension ? `./${componentName}.${componentExt}` : `./${componentName}`;
|
|
1072
1502
|
if (usesDefaultExport) {
|
|
1073
|
-
return `export { default as ${componentName} } from '
|
|
1503
|
+
return `export { default as ${componentName} } from '${importPath}'`;
|
|
1074
1504
|
} else {
|
|
1075
|
-
return `export { ${componentName} } from '
|
|
1505
|
+
return `export { ${componentName} } from '${importPath}'`;
|
|
1076
1506
|
}
|
|
1077
1507
|
}).join("\n");
|
|
1078
|
-
const indexPath =
|
|
1508
|
+
const indexPath = import_node_path5.default.join(config.output, `index.${ext}`);
|
|
1079
1509
|
if (dryRun) {
|
|
1080
1510
|
console.log(` index.${ext}`);
|
|
1081
1511
|
} else {
|
|
1082
|
-
await
|
|
1512
|
+
await writeFile2(indexPath, `${exports2}
|
|
1083
1513
|
`);
|
|
1084
1514
|
}
|
|
1085
1515
|
}
|
|
1086
1516
|
async function generatePreviewHtml(svgFiles, config) {
|
|
1087
1517
|
const componentNames = svgFiles.map((svgFile) => {
|
|
1088
|
-
const fileName =
|
|
1518
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1089
1519
|
return getComponentName(
|
|
1090
1520
|
fileName,
|
|
1091
1521
|
config.prefix,
|
|
1092
1522
|
config.suffix,
|
|
1093
|
-
config.
|
|
1523
|
+
config.componentNameTransform
|
|
1094
1524
|
);
|
|
1095
1525
|
});
|
|
1096
1526
|
const svgContents = await Promise.all(
|
|
1097
1527
|
svgFiles.map(async (svgFile) => {
|
|
1098
|
-
return await
|
|
1528
|
+
return await readFile3(svgFile);
|
|
1099
1529
|
})
|
|
1100
1530
|
);
|
|
1101
1531
|
const html = `<!DOCTYPE html>
|
|
@@ -1257,8 +1687,8 @@ async function generatePreviewHtml(svgFiles, config) {
|
|
|
1257
1687
|
</script>
|
|
1258
1688
|
</body>
|
|
1259
1689
|
</html>`;
|
|
1260
|
-
const previewPath =
|
|
1261
|
-
await
|
|
1690
|
+
const previewPath = import_node_path5.default.join(config.output, "preview.html");
|
|
1691
|
+
await writeFile2(previewPath, html);
|
|
1262
1692
|
}
|
|
1263
1693
|
async function cleanOutputDirectory(svgFiles, config) {
|
|
1264
1694
|
const { readdir, unlink } = await import("fs/promises");
|
|
@@ -1266,12 +1696,12 @@ async function cleanOutputDirectory(svgFiles, config) {
|
|
|
1266
1696
|
const fileExt = strategy.getComponentExtension(config.typescript ?? true);
|
|
1267
1697
|
const expectedComponents = new Set(
|
|
1268
1698
|
svgFiles.map((svgFile) => {
|
|
1269
|
-
const fileName =
|
|
1699
|
+
const fileName = import_node_path5.default.basename(svgFile, ".svg");
|
|
1270
1700
|
const componentName = getComponentName(
|
|
1271
1701
|
fileName,
|
|
1272
1702
|
config.prefix,
|
|
1273
1703
|
config.suffix,
|
|
1274
|
-
config.
|
|
1704
|
+
config.componentNameTransform
|
|
1275
1705
|
);
|
|
1276
1706
|
return `${componentName}.${fileExt}`;
|
|
1277
1707
|
})
|
|
@@ -1293,7 +1723,7 @@ async function cleanOutputDirectory(svgFiles, config) {
|
|
|
1293
1723
|
continue;
|
|
1294
1724
|
}
|
|
1295
1725
|
if (!expectedComponents.has(file)) {
|
|
1296
|
-
const filePath =
|
|
1726
|
+
const filePath = import_node_path5.default.join(config.output, file);
|
|
1297
1727
|
await unlink(filePath);
|
|
1298
1728
|
console.log(`Deleted orphaned component: ${file}`);
|
|
1299
1729
|
}
|
|
@@ -1325,9 +1755,19 @@ async function generate(options = {}) {
|
|
|
1325
1755
|
${import_chalk.default.bold("Files that would be generated:")}
|
|
1326
1756
|
`);
|
|
1327
1757
|
}
|
|
1758
|
+
const useIncremental = config.incremental?.enabled !== false && !options.force && !options.dryRun;
|
|
1759
|
+
let cacheManager = null;
|
|
1760
|
+
if (useIncremental) {
|
|
1761
|
+
const cacheDir = config.incremental?.cacheDir || ".vectify";
|
|
1762
|
+
cacheManager = new CacheManager(config.output, cacheDir);
|
|
1763
|
+
await cacheManager.load();
|
|
1764
|
+
}
|
|
1765
|
+
if (options.force) {
|
|
1766
|
+
spinner.info(import_chalk.default.yellow("Force mode - ignoring cache, regenerating all icons"));
|
|
1767
|
+
}
|
|
1328
1768
|
const actionText = options.dryRun ? "Analyzing icons..." : "Generating icon components...";
|
|
1329
1769
|
spinner.start(actionText);
|
|
1330
|
-
const stats = await generateIcons(config, options.dryRun);
|
|
1770
|
+
const stats = cacheManager ? await generateIconsIncremental(config, cacheManager, options.dryRun) : await generateIcons(config, options.dryRun);
|
|
1331
1771
|
if (stats.failed > 0) {
|
|
1332
1772
|
spinner.warn(`${options.dryRun ? "Analyzed" : "Generated"} ${import_chalk.default.green(stats.success)} icons, ${import_chalk.default.red(stats.failed)} failed`);
|
|
1333
1773
|
if (stats.errors.length > 0) {
|
|
@@ -1360,7 +1800,7 @@ ${import_chalk.default.bold("Output:")} ${import_chalk.default.cyan(config.outpu
|
|
|
1360
1800
|
}
|
|
1361
1801
|
|
|
1362
1802
|
// src/commands/init.ts
|
|
1363
|
-
var
|
|
1803
|
+
var import_node_path6 = __toESM(require("path"));
|
|
1364
1804
|
var import_node_process3 = __toESM(require("process"));
|
|
1365
1805
|
var import_chalk2 = __toESM(require("chalk"));
|
|
1366
1806
|
var import_inquirer = __toESM(require("inquirer"));
|
|
@@ -1390,8 +1830,8 @@ Note: Project root detected at ${import_chalk2.default.cyan(projectRoot)}`));
|
|
|
1390
1830
|
}
|
|
1391
1831
|
}
|
|
1392
1832
|
]);
|
|
1393
|
-
const configPath =
|
|
1394
|
-
const configDir =
|
|
1833
|
+
const configPath = import_node_path6.default.resolve(projectRoot, pathAnswers.configPath);
|
|
1834
|
+
const configDir = import_node_path6.default.dirname(configPath);
|
|
1395
1835
|
if (!options.force && await fileExists(configPath)) {
|
|
1396
1836
|
const { overwrite } = await import_inquirer.default.prompt([
|
|
1397
1837
|
{
|
|
@@ -1465,18 +1905,18 @@ Note: Project root detected at ${import_chalk2.default.cyan(projectRoot)}`));
|
|
|
1465
1905
|
default: ""
|
|
1466
1906
|
}
|
|
1467
1907
|
]);
|
|
1468
|
-
const inputPath =
|
|
1469
|
-
const outputPath =
|
|
1908
|
+
const inputPath = import_node_path6.default.resolve(projectRoot, answers.input);
|
|
1909
|
+
const outputPath = import_node_path6.default.resolve(projectRoot, answers.output);
|
|
1470
1910
|
const spinner = (0, import_ora2.default)("Setting up directories...").start();
|
|
1471
1911
|
await ensureDir(inputPath);
|
|
1472
1912
|
spinner.text = `Created input directory: ${import_chalk2.default.cyan(answers.input)}`;
|
|
1473
1913
|
await ensureDir(outputPath);
|
|
1474
1914
|
spinner.succeed(`Created output directory: ${import_chalk2.default.cyan(answers.output)}`);
|
|
1475
|
-
const relativeConfigDir =
|
|
1915
|
+
const relativeConfigDir = import_node_path6.default.relative(configDir, projectRoot) || ".";
|
|
1476
1916
|
const finalFramework = answers.vueVersion || answers.framework;
|
|
1477
1917
|
const configContent = generateConfigContent({ ...answers, framework: finalFramework }, relativeConfigDir);
|
|
1478
1918
|
spinner.start("Creating config file...");
|
|
1479
|
-
await
|
|
1919
|
+
await writeFile2(configPath, configContent);
|
|
1480
1920
|
spinner.succeed(`Config file created at ${import_chalk2.default.green(configPath)}`);
|
|
1481
1921
|
console.log(`
|
|
1482
1922
|
${import_chalk2.default.bold("Next steps:")}`);
|
|
@@ -1516,10 +1956,93 @@ export default defineConfig({
|
|
|
1516
1956
|
}
|
|
1517
1957
|
|
|
1518
1958
|
// src/commands/watch.ts
|
|
1519
|
-
var
|
|
1959
|
+
var import_node_path7 = __toESM(require("path"));
|
|
1520
1960
|
var import_chalk3 = __toESM(require("chalk"));
|
|
1521
1961
|
var import_chokidar = __toESM(require("chokidar"));
|
|
1522
1962
|
var import_ora3 = __toESM(require("ora"));
|
|
1963
|
+
|
|
1964
|
+
// src/cache/svg-validator.ts
|
|
1965
|
+
var import_promises3 = require("fs/promises");
|
|
1966
|
+
var import_cheerio = require("cheerio");
|
|
1967
|
+
var MIN_SVG_SIZE = 20;
|
|
1968
|
+
var DRAWABLE_ELEMENTS = [
|
|
1969
|
+
"path",
|
|
1970
|
+
"circle",
|
|
1971
|
+
"rect",
|
|
1972
|
+
"ellipse",
|
|
1973
|
+
"line",
|
|
1974
|
+
"polyline",
|
|
1975
|
+
"polygon",
|
|
1976
|
+
"text",
|
|
1977
|
+
"image",
|
|
1978
|
+
"use"
|
|
1979
|
+
];
|
|
1980
|
+
async function validateSVGFile(filePath) {
|
|
1981
|
+
try {
|
|
1982
|
+
const stats = await (0, import_promises3.stat)(filePath);
|
|
1983
|
+
if (stats.size < MIN_SVG_SIZE) {
|
|
1984
|
+
return {
|
|
1985
|
+
isValid: false,
|
|
1986
|
+
isEmpty: true,
|
|
1987
|
+
reason: "File is too small to be a valid SVG"
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
const content = await (0, import_promises3.readFile)(filePath, "utf-8");
|
|
1991
|
+
if (!content.trim()) {
|
|
1992
|
+
return {
|
|
1993
|
+
isValid: false,
|
|
1994
|
+
isEmpty: true,
|
|
1995
|
+
reason: "File is empty"
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
if (!content.includes("<svg")) {
|
|
1999
|
+
return {
|
|
2000
|
+
isValid: false,
|
|
2001
|
+
isEmpty: false,
|
|
2002
|
+
reason: "File does not contain <svg> tag"
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
if (!hasDrawableContent(content)) {
|
|
2006
|
+
return {
|
|
2007
|
+
isValid: false,
|
|
2008
|
+
isEmpty: true,
|
|
2009
|
+
reason: "SVG has no drawable content"
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
try {
|
|
2013
|
+
const $ = (0, import_cheerio.load)(content, { xmlMode: true });
|
|
2014
|
+
const svgElement = $("svg");
|
|
2015
|
+
if (svgElement.length === 0) {
|
|
2016
|
+
return {
|
|
2017
|
+
isValid: false,
|
|
2018
|
+
isEmpty: false,
|
|
2019
|
+
reason: "Failed to parse SVG element"
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
return {
|
|
2023
|
+
isValid: true,
|
|
2024
|
+
isEmpty: false
|
|
2025
|
+
};
|
|
2026
|
+
} catch (parseError) {
|
|
2027
|
+
return {
|
|
2028
|
+
isValid: false,
|
|
2029
|
+
isEmpty: false,
|
|
2030
|
+
reason: `Failed to parse SVG: ${parseError}`
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
} catch (error) {
|
|
2034
|
+
return {
|
|
2035
|
+
isValid: false,
|
|
2036
|
+
isEmpty: false,
|
|
2037
|
+
reason: `Failed to read file: ${error}`
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function hasDrawableContent(content) {
|
|
2042
|
+
return DRAWABLE_ELEMENTS.some((element) => content.includes(`<${element}`));
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
// src/commands/watch.ts
|
|
1523
2046
|
async function watch(options = {}) {
|
|
1524
2047
|
const spinner = (0, import_ora3.default)("Loading configuration...").start();
|
|
1525
2048
|
try {
|
|
@@ -1535,16 +2058,24 @@ async function watch(options = {}) {
|
|
|
1535
2058
|
}
|
|
1536
2059
|
const config = await loadConfig(configPath);
|
|
1537
2060
|
spinner.succeed(`Config loaded from ${import_chalk3.default.green(configPath)}`);
|
|
2061
|
+
const useIncremental = config.incremental?.enabled !== false;
|
|
2062
|
+
const cacheDir = config.incremental?.cacheDir || ".vectify";
|
|
2063
|
+
const cacheManager = useIncremental ? new CacheManager(config.output, cacheDir) : null;
|
|
2064
|
+
if (cacheManager) {
|
|
2065
|
+
await cacheManager.load();
|
|
2066
|
+
}
|
|
1538
2067
|
spinner.start("Generating icon components...");
|
|
1539
|
-
const initialStats = await generateIcons(config);
|
|
2068
|
+
const initialStats = useIncremental && cacheManager ? await generateIconsIncremental(config, cacheManager) : await generateIcons(config);
|
|
1540
2069
|
spinner.succeed(`Generated ${import_chalk3.default.green(initialStats.success)} icon components`);
|
|
1541
|
-
const watchPath =
|
|
2070
|
+
const watchPath = import_node_path7.default.join(config.input, "**/*.svg");
|
|
1542
2071
|
const debounce = config.watch?.debounce ?? 300;
|
|
1543
2072
|
const ignore = config.watch?.ignore ?? ["**/node_modules/**", "**/.git/**"];
|
|
2073
|
+
const emptyFileRetryDelay = config.watch?.emptyFileRetryDelay ?? 2e3;
|
|
1544
2074
|
console.log(import_chalk3.default.bold("\nWatching for changes..."));
|
|
1545
2075
|
console.log(` ${import_chalk3.default.cyan(watchPath)}`);
|
|
1546
2076
|
console.log(` ${import_chalk3.default.gray("Press Ctrl+C to stop")}
|
|
1547
2077
|
`);
|
|
2078
|
+
const pendingChanges = /* @__PURE__ */ new Map();
|
|
1548
2079
|
const debounceTimer = null;
|
|
1549
2080
|
const watcher = import_chokidar.default.watch(watchPath, {
|
|
1550
2081
|
ignored: ignore,
|
|
@@ -1552,12 +2083,12 @@ async function watch(options = {}) {
|
|
|
1552
2083
|
ignoreInitial: true
|
|
1553
2084
|
});
|
|
1554
2085
|
watcher.on("add", (filePath) => {
|
|
1555
|
-
handleChange("added", filePath, config, debounce, debounceTimer);
|
|
2086
|
+
handleChange("added", filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, debounceTimer);
|
|
1556
2087
|
}).on("change", (filePath) => {
|
|
1557
|
-
handleChange("changed", filePath, config, debounce, debounceTimer);
|
|
2088
|
+
handleChange("changed", filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, debounceTimer);
|
|
1558
2089
|
}).on("unlink", (filePath) => {
|
|
1559
|
-
console.log(import_chalk3.default.yellow(`SVG file removed: ${
|
|
1560
|
-
handleChange("removed", filePath, config, debounce, debounceTimer);
|
|
2090
|
+
console.log(import_chalk3.default.yellow(`SVG file removed: ${import_node_path7.default.basename(filePath)}`));
|
|
2091
|
+
handleChange("removed", filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, debounceTimer);
|
|
1561
2092
|
}).on("error", (error) => {
|
|
1562
2093
|
console.error(import_chalk3.default.red(`Watcher error: ${error.message}`));
|
|
1563
2094
|
});
|
|
@@ -1574,23 +2105,51 @@ ${import_chalk3.default.yellow("Stopping watch mode...")}`);
|
|
|
1574
2105
|
throw error;
|
|
1575
2106
|
}
|
|
1576
2107
|
}
|
|
1577
|
-
function handleChange(event, filePath, config, debounce, timer) {
|
|
1578
|
-
|
|
2108
|
+
function handleChange(event, filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, timer) {
|
|
2109
|
+
pendingChanges.set(filePath, event);
|
|
1579
2110
|
if (timer) {
|
|
1580
2111
|
clearTimeout(timer);
|
|
1581
2112
|
}
|
|
1582
2113
|
timer = setTimeout(async () => {
|
|
1583
|
-
const
|
|
2114
|
+
const changes = Array.from(pendingChanges.entries());
|
|
2115
|
+
pendingChanges.clear();
|
|
2116
|
+
const validChanges = [];
|
|
2117
|
+
const invalidFiles = [];
|
|
2118
|
+
for (const [file, changeEvent] of changes) {
|
|
2119
|
+
if (changeEvent === "removed") {
|
|
2120
|
+
validChanges.push([file, changeEvent]);
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
const validation = await validateSVGFile(file);
|
|
2124
|
+
if (!validation.isValid) {
|
|
2125
|
+
if (validation.isEmpty) {
|
|
2126
|
+
console.log(import_chalk3.default.yellow(`\u23F3 Waiting for content: ${import_node_path7.default.basename(file)}`));
|
|
2127
|
+
setTimeout(() => {
|
|
2128
|
+
handleChange(changeEvent, file, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, timer);
|
|
2129
|
+
}, emptyFileRetryDelay);
|
|
2130
|
+
} else {
|
|
2131
|
+
console.error(import_chalk3.default.red(`\u274C Invalid SVG: ${import_node_path7.default.basename(file)} - ${validation.reason}`));
|
|
2132
|
+
invalidFiles.push(file);
|
|
2133
|
+
}
|
|
2134
|
+
continue;
|
|
2135
|
+
}
|
|
2136
|
+
validChanges.push([file, changeEvent]);
|
|
2137
|
+
}
|
|
2138
|
+
if (validChanges.length === 0) {
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
const spinner = (0, import_ora3.default)(`Processing ${validChanges.length} change(s)...`).start();
|
|
1584
2142
|
try {
|
|
1585
|
-
const stats = await generateIcons(config);
|
|
2143
|
+
const stats = cacheManager ? await generateIconsIncremental(config, cacheManager) : await generateIcons(config);
|
|
1586
2144
|
if (stats.failed > 0) {
|
|
1587
2145
|
spinner.warn(
|
|
1588
2146
|
`Regenerated ${import_chalk3.default.green(stats.success)} icons, ${import_chalk3.default.red(stats.failed)} failed`
|
|
1589
2147
|
);
|
|
1590
2148
|
} else {
|
|
1591
|
-
spinner.succeed(
|
|
2149
|
+
spinner.succeed(`\u2713 Updated ${import_chalk3.default.green(stats.success)} icon components`);
|
|
1592
2150
|
}
|
|
1593
|
-
|
|
2151
|
+
const triggerFiles = validChanges.map(([file, evt]) => `${import_node_path7.default.basename(file)} (${evt})`).join(", ");
|
|
2152
|
+
console.log(import_chalk3.default.gray(` Triggered by: ${triggerFiles}
|
|
1594
2153
|
`));
|
|
1595
2154
|
} catch (error) {
|
|
1596
2155
|
spinner.fail("Regeneration failed");
|