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/cli.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
|
}
|
|
@@ -133,8 +133,8 @@ var init_helpers = __esm({
|
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
// src/cli.ts
|
|
136
|
-
var
|
|
137
|
-
var
|
|
136
|
+
var import_node_fs3 = require("fs");
|
|
137
|
+
var import_node_path8 = require("path");
|
|
138
138
|
var import_node_url2 = require("url");
|
|
139
139
|
var import_chalk4 = __toESM(require("chalk"));
|
|
140
140
|
var import_commander = require("commander");
|
|
@@ -143,8 +143,288 @@ var import_commander = require("commander");
|
|
|
143
143
|
var import_chalk = __toESM(require("chalk"));
|
|
144
144
|
var import_ora = __toESM(require("ora"));
|
|
145
145
|
|
|
146
|
+
// src/cache/cache-manager.ts
|
|
147
|
+
var import_node_fs = require("fs");
|
|
148
|
+
var import_promises2 = require("fs/promises");
|
|
149
|
+
var import_node_path = require("path");
|
|
150
|
+
|
|
151
|
+
// src/cache/hash-utils.ts
|
|
152
|
+
var import_node_crypto = require("crypto");
|
|
153
|
+
var import_promises = require("fs/promises");
|
|
154
|
+
function hashContent(content) {
|
|
155
|
+
return (0, import_node_crypto.createHash)("sha256").update(content).digest("hex");
|
|
156
|
+
}
|
|
157
|
+
async function hashFile(filePath) {
|
|
158
|
+
try {
|
|
159
|
+
const content = await (0, import_promises.readFile)(filePath, "utf-8");
|
|
160
|
+
return hashContent(content);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
throw new Error(`Failed to hash file ${filePath}: ${error}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function hashConfig(config) {
|
|
166
|
+
const relevantConfig = {
|
|
167
|
+
framework: config.framework,
|
|
168
|
+
typescript: config.typescript,
|
|
169
|
+
keepColors: config.keepColors,
|
|
170
|
+
prefix: config.prefix,
|
|
171
|
+
suffix: config.suffix,
|
|
172
|
+
optimize: config.optimize,
|
|
173
|
+
svgoConfig: config.svgoConfig,
|
|
174
|
+
componentNameTransform: config.componentNameTransform?.toString()
|
|
175
|
+
};
|
|
176
|
+
return hashContent(JSON.stringify(relevantConfig));
|
|
177
|
+
}
|
|
178
|
+
function hashSvgoConfig(svgoConfig) {
|
|
179
|
+
return hashContent(JSON.stringify(svgoConfig || {}));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/cache/cache-manager.ts
|
|
183
|
+
var CACHE_VERSION = "1.0.0";
|
|
184
|
+
var CacheManager = class {
|
|
185
|
+
constructor(outputDir, cacheDir = ".vectify") {
|
|
186
|
+
this.cache = {
|
|
187
|
+
version: CACHE_VERSION,
|
|
188
|
+
configHash: "",
|
|
189
|
+
entries: {},
|
|
190
|
+
baseComponentHash: ""
|
|
191
|
+
};
|
|
192
|
+
this.cacheFilePath = (0, import_node_path.join)(outputDir, cacheDir, "cache.json");
|
|
193
|
+
this.stats = {
|
|
194
|
+
hits: 0,
|
|
195
|
+
misses: 0,
|
|
196
|
+
total: 0,
|
|
197
|
+
timeSaved: 0
|
|
198
|
+
};
|
|
199
|
+
this.isDirty = false;
|
|
200
|
+
process.on("beforeExit", () => {
|
|
201
|
+
if (this.isDirty) {
|
|
202
|
+
this.saveSync();
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Load cache from disk
|
|
208
|
+
*/
|
|
209
|
+
async load() {
|
|
210
|
+
try {
|
|
211
|
+
if (!(0, import_node_fs.existsSync)(this.cacheFilePath)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const content = await (0, import_promises2.readFile)(this.cacheFilePath, "utf-8");
|
|
215
|
+
const loadedCache = JSON.parse(content);
|
|
216
|
+
if (loadedCache.version !== CACHE_VERSION) {
|
|
217
|
+
console.log("\u26A0\uFE0F Cache version mismatch, rebuilding cache...");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.cache = loadedCache;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.warn("\u26A0\uFE0F Failed to load cache, starting fresh:", error);
|
|
223
|
+
this.cache = {
|
|
224
|
+
version: CACHE_VERSION,
|
|
225
|
+
configHash: "",
|
|
226
|
+
entries: {},
|
|
227
|
+
baseComponentHash: ""
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Save cache to disk (atomic write)
|
|
233
|
+
*/
|
|
234
|
+
async save() {
|
|
235
|
+
try {
|
|
236
|
+
const cacheDir = (0, import_node_path.dirname)(this.cacheFilePath);
|
|
237
|
+
await (0, import_promises2.mkdir)(cacheDir, { recursive: true });
|
|
238
|
+
const tempPath = `${this.cacheFilePath}.tmp`;
|
|
239
|
+
await (0, import_promises2.writeFile)(tempPath, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
240
|
+
await (0, import_promises2.writeFile)(this.cacheFilePath, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
241
|
+
this.isDirty = false;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.warn("\u26A0\uFE0F Failed to save cache:", error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Synchronous save for process exit
|
|
248
|
+
*/
|
|
249
|
+
saveSync() {
|
|
250
|
+
try {
|
|
251
|
+
const fs2 = require("fs");
|
|
252
|
+
const cacheDir = (0, import_node_path.dirname)(this.cacheFilePath);
|
|
253
|
+
if (!fs2.existsSync(cacheDir)) {
|
|
254
|
+
fs2.mkdirSync(cacheDir, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
fs2.writeFileSync(this.cacheFilePath, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
257
|
+
this.isDirty = false;
|
|
258
|
+
} catch {
|
|
259
|
+
console.warn("\u26A0\uFE0F Failed to save cache on exit");
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Check if a file needs regeneration
|
|
264
|
+
*/
|
|
265
|
+
async needsRegeneration(svgPath, componentPath, config) {
|
|
266
|
+
this.stats.total++;
|
|
267
|
+
if (!(0, import_node_fs.existsSync)(componentPath)) {
|
|
268
|
+
this.stats.misses++;
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
const entry = this.cache.entries[svgPath];
|
|
272
|
+
if (!entry) {
|
|
273
|
+
this.stats.misses++;
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
const stats = await (0, import_promises2.stat)(svgPath);
|
|
278
|
+
const currentMtime = stats.mtimeMs;
|
|
279
|
+
if (currentMtime === entry.svgMtime) {
|
|
280
|
+
if (!this.isConfigMatching(entry, config)) {
|
|
281
|
+
this.stats.misses++;
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
this.stats.hits++;
|
|
285
|
+
this.stats.timeSaved += 50;
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
const currentHash = await hashFile(svgPath);
|
|
289
|
+
if (currentHash === entry.svgHash) {
|
|
290
|
+
entry.svgMtime = currentMtime;
|
|
291
|
+
this.isDirty = true;
|
|
292
|
+
this.stats.hits++;
|
|
293
|
+
this.stats.timeSaved += 50;
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
this.stats.misses++;
|
|
297
|
+
return true;
|
|
298
|
+
} catch {
|
|
299
|
+
this.stats.misses++;
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Check if config matches cache entry
|
|
305
|
+
*/
|
|
306
|
+
isConfigMatching(entry, config) {
|
|
307
|
+
const snapshot = entry.configSnapshot;
|
|
308
|
+
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);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Update cache entry after successful generation
|
|
312
|
+
*/
|
|
313
|
+
async updateEntry(svgPath, componentPath, componentName, componentHash, config) {
|
|
314
|
+
try {
|
|
315
|
+
const svgHash = await hashFile(svgPath);
|
|
316
|
+
const stats = await (0, import_promises2.stat)(svgPath);
|
|
317
|
+
this.cache.entries[svgPath] = {
|
|
318
|
+
svgPath,
|
|
319
|
+
svgHash,
|
|
320
|
+
svgMtime: stats.mtimeMs,
|
|
321
|
+
componentName,
|
|
322
|
+
componentPath,
|
|
323
|
+
componentHash,
|
|
324
|
+
configSnapshot: {
|
|
325
|
+
framework: config.framework,
|
|
326
|
+
typescript: config.typescript ?? true,
|
|
327
|
+
keepColors: config.keepColors ?? false,
|
|
328
|
+
prefix: config.prefix || "",
|
|
329
|
+
suffix: config.suffix || "",
|
|
330
|
+
optimize: config.optimize ?? true,
|
|
331
|
+
svgoConfigHash: hashSvgoConfig(config.svgoConfig)
|
|
332
|
+
},
|
|
333
|
+
generatedAt: Date.now()
|
|
334
|
+
};
|
|
335
|
+
this.isDirty = true;
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.warn(`\u26A0\uFE0F Failed to update cache entry for ${svgPath}:`, error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Remove cache entry
|
|
342
|
+
*/
|
|
343
|
+
removeEntry(svgPath) {
|
|
344
|
+
if (this.cache.entries[svgPath]) {
|
|
345
|
+
delete this.cache.entries[svgPath];
|
|
346
|
+
this.isDirty = true;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Update config hash
|
|
351
|
+
*/
|
|
352
|
+
updateConfigHash(config) {
|
|
353
|
+
const newHash = hashConfig(config);
|
|
354
|
+
if (this.cache.configHash !== newHash) {
|
|
355
|
+
this.cache.configHash = newHash;
|
|
356
|
+
this.isDirty = true;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Update base component hash
|
|
361
|
+
*/
|
|
362
|
+
updateBaseComponentHash(hash) {
|
|
363
|
+
if (this.cache.baseComponentHash !== hash) {
|
|
364
|
+
this.cache.baseComponentHash = hash;
|
|
365
|
+
this.isDirty = true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Check if config has changed (invalidates all cache)
|
|
370
|
+
*/
|
|
371
|
+
hasConfigChanged(config) {
|
|
372
|
+
const currentHash = hashConfig(config);
|
|
373
|
+
return this.cache.configHash !== "" && this.cache.configHash !== currentHash;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Invalidate all cache entries
|
|
377
|
+
*/
|
|
378
|
+
invalidateAll() {
|
|
379
|
+
this.cache.entries = {};
|
|
380
|
+
this.isDirty = true;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Clean stale entries (files that no longer exist)
|
|
384
|
+
*/
|
|
385
|
+
async cleanStaleEntries(existingSvgPaths) {
|
|
386
|
+
const existingSet = new Set(existingSvgPaths);
|
|
387
|
+
let cleaned = 0;
|
|
388
|
+
for (const svgPath of Object.keys(this.cache.entries)) {
|
|
389
|
+
if (!existingSet.has(svgPath)) {
|
|
390
|
+
delete this.cache.entries[svgPath];
|
|
391
|
+
cleaned++;
|
|
392
|
+
this.isDirty = true;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (cleaned > 0) {
|
|
396
|
+
console.log(`\u{1F9F9} Cleaned ${cleaned} stale cache entries`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get cache statistics
|
|
401
|
+
*/
|
|
402
|
+
getStats() {
|
|
403
|
+
return { ...this.stats };
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Reset statistics
|
|
407
|
+
*/
|
|
408
|
+
resetStats() {
|
|
409
|
+
this.stats = {
|
|
410
|
+
hits: 0,
|
|
411
|
+
misses: 0,
|
|
412
|
+
total: 0,
|
|
413
|
+
timeSaved: 0
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Get cache hit rate
|
|
418
|
+
*/
|
|
419
|
+
getHitRate() {
|
|
420
|
+
if (this.stats.total === 0)
|
|
421
|
+
return 0;
|
|
422
|
+
return this.stats.hits / this.stats.total * 100;
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
|
|
146
426
|
// src/config/loader.ts
|
|
147
|
-
var
|
|
427
|
+
var import_node_path3 = __toESM(require("path"));
|
|
148
428
|
var import_node_process = __toESM(require("process"));
|
|
149
429
|
var import_jiti = require("jiti");
|
|
150
430
|
|
|
@@ -168,6 +448,7 @@ function parseSvg(svgContent) {
|
|
|
168
448
|
if (svgElement.length === 0) {
|
|
169
449
|
throw new Error("Invalid SVG: No <svg> tag found");
|
|
170
450
|
}
|
|
451
|
+
const viewBox = svgElement.attr("viewBox") || "0 0 24 24";
|
|
171
452
|
const iconNodes = [];
|
|
172
453
|
svgElement.children().each((_, element) => {
|
|
173
454
|
const node = parseElement($, element);
|
|
@@ -175,7 +456,29 @@ function parseSvg(svgContent) {
|
|
|
175
456
|
iconNodes.push(node);
|
|
176
457
|
}
|
|
177
458
|
});
|
|
178
|
-
|
|
459
|
+
const isMultiColor = detectMultiColor(iconNodes);
|
|
460
|
+
return { iconNodes, viewBox, isMultiColor };
|
|
461
|
+
}
|
|
462
|
+
function detectMultiColor(nodes) {
|
|
463
|
+
const colors = /* @__PURE__ */ new Set();
|
|
464
|
+
function collectColors(node) {
|
|
465
|
+
const [, attrs, children] = node;
|
|
466
|
+
if (attrs.fill && attrs.fill !== "none" && attrs.fill !== "transparent") {
|
|
467
|
+
colors.add(String(attrs.fill).toLowerCase());
|
|
468
|
+
}
|
|
469
|
+
if (attrs.stroke && attrs.stroke !== "none" && attrs.stroke !== "transparent") {
|
|
470
|
+
colors.add(String(attrs.stroke).toLowerCase());
|
|
471
|
+
}
|
|
472
|
+
if (children && children.length > 0) {
|
|
473
|
+
children.forEach(collectColors);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
nodes.forEach(collectColors);
|
|
477
|
+
const realColors = Array.from(colors).filter((color) => {
|
|
478
|
+
const c = color.toLowerCase();
|
|
479
|
+
return c !== "currentcolor";
|
|
480
|
+
});
|
|
481
|
+
return realColors.length >= 2;
|
|
179
482
|
}
|
|
180
483
|
function parseElement($, element) {
|
|
181
484
|
if (element.type !== "tag") {
|
|
@@ -246,22 +549,22 @@ function formatAttrs(attrs) {
|
|
|
246
549
|
}
|
|
247
550
|
|
|
248
551
|
// src/generators/templates/template-engine.ts
|
|
249
|
-
var
|
|
250
|
-
var
|
|
552
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
553
|
+
var import_node_path2 = __toESM(require("path"));
|
|
251
554
|
var import_node_url = require("url");
|
|
252
555
|
var import_handlebars = __toESM(require("handlebars"));
|
|
253
556
|
var import_meta = {};
|
|
254
557
|
function getTemplatesDir() {
|
|
255
558
|
if (typeof __dirname !== "undefined") {
|
|
256
|
-
return
|
|
559
|
+
return import_node_path2.default.join(__dirname, "templates");
|
|
257
560
|
}
|
|
258
561
|
const currentFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
259
|
-
return
|
|
562
|
+
return import_node_path2.default.join(import_node_path2.default.dirname(currentFile), "templates");
|
|
260
563
|
}
|
|
261
564
|
function loadTemplate(templatePath) {
|
|
262
565
|
const templatesDir = getTemplatesDir();
|
|
263
|
-
const fullPath =
|
|
264
|
-
const templateContent =
|
|
566
|
+
const fullPath = import_node_path2.default.join(templatesDir, templatePath);
|
|
567
|
+
const templateContent = import_node_fs2.default.readFileSync(fullPath, "utf-8");
|
|
265
568
|
return import_handlebars.default.compile(templateContent, { noEscape: true });
|
|
266
569
|
}
|
|
267
570
|
function renderTemplate(templatePath, data) {
|
|
@@ -305,14 +608,15 @@ function getQwikTemplatePath(typescript, type) {
|
|
|
305
608
|
function getAngularTemplatePath(type) {
|
|
306
609
|
return `angular/${type}.ts.hbs`;
|
|
307
610
|
}
|
|
308
|
-
function generateAngularComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
611
|
+
function generateAngularComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
309
612
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
310
613
|
const templatePath = getAngularTemplatePath("component");
|
|
311
614
|
return renderTemplate(templatePath, {
|
|
312
615
|
componentName,
|
|
313
616
|
formattedNodes,
|
|
314
617
|
typescript,
|
|
315
|
-
keepColors
|
|
618
|
+
keepColors,
|
|
619
|
+
viewBox
|
|
316
620
|
});
|
|
317
621
|
}
|
|
318
622
|
function generateAngularBaseComponent(typescript) {
|
|
@@ -327,14 +631,15 @@ function generateAngularBaseComponent(typescript) {
|
|
|
327
631
|
function getAstroTemplatePath(type) {
|
|
328
632
|
return `astro/${type}.astro.hbs`;
|
|
329
633
|
}
|
|
330
|
-
function generateAstroComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
634
|
+
function generateAstroComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
331
635
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
332
636
|
const templatePath = getAstroTemplatePath("component");
|
|
333
637
|
return renderTemplate(templatePath, {
|
|
334
638
|
componentName,
|
|
335
639
|
formattedNodes,
|
|
336
640
|
typescript,
|
|
337
|
-
keepColors
|
|
641
|
+
keepColors,
|
|
642
|
+
viewBox
|
|
338
643
|
});
|
|
339
644
|
}
|
|
340
645
|
function generateAstroBaseComponent(typescript) {
|
|
@@ -350,14 +655,15 @@ function getLitTemplatePath(typescript, type) {
|
|
|
350
655
|
const ext = typescript ? "ts" : "js";
|
|
351
656
|
return `lit/${type}.${ext}.hbs`;
|
|
352
657
|
}
|
|
353
|
-
function generateLitComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
658
|
+
function generateLitComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
354
659
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
355
660
|
const templatePath = getLitTemplatePath(typescript, "component");
|
|
356
661
|
return renderTemplate(templatePath, {
|
|
357
662
|
componentName,
|
|
358
663
|
formattedNodes,
|
|
359
664
|
typescript,
|
|
360
|
-
keepColors
|
|
665
|
+
keepColors,
|
|
666
|
+
viewBox
|
|
361
667
|
});
|
|
362
668
|
}
|
|
363
669
|
function generateLitBaseComponent(typescript) {
|
|
@@ -369,14 +675,15 @@ function generateLitBaseComponent(typescript) {
|
|
|
369
675
|
}
|
|
370
676
|
|
|
371
677
|
// src/generators/react.ts
|
|
372
|
-
function generateReactComponent(componentName, iconNode, typescript, keepColors = false) {
|
|
678
|
+
function generateReactComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
373
679
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
374
680
|
const templatePath = getReactTemplatePath(typescript, "component");
|
|
375
681
|
return renderTemplate(templatePath, {
|
|
376
682
|
typescript,
|
|
377
683
|
componentName,
|
|
378
684
|
formattedNodes,
|
|
379
|
-
keepColors
|
|
685
|
+
keepColors,
|
|
686
|
+
viewBox
|
|
380
687
|
});
|
|
381
688
|
}
|
|
382
689
|
function generateCreateIcon(typescript) {
|
|
@@ -385,7 +692,7 @@ function generateCreateIcon(typescript) {
|
|
|
385
692
|
}
|
|
386
693
|
|
|
387
694
|
// src/generators/react-like.ts
|
|
388
|
-
function generateReactLikeComponent(componentName, iconNode, typescript, keepColors, framework) {
|
|
695
|
+
function generateReactLikeComponent(componentName, iconNode, typescript, keepColors, viewBox, framework) {
|
|
389
696
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
390
697
|
let templatePath;
|
|
391
698
|
if (framework === "solid") {
|
|
@@ -401,7 +708,8 @@ function generateReactLikeComponent(componentName, iconNode, typescript, keepCol
|
|
|
401
708
|
componentName,
|
|
402
709
|
formattedNodes,
|
|
403
710
|
typescript,
|
|
404
|
-
keepColors
|
|
711
|
+
keepColors,
|
|
712
|
+
viewBox
|
|
405
713
|
});
|
|
406
714
|
}
|
|
407
715
|
function generateReactLikeBaseComponent(typescript, framework) {
|
|
@@ -422,12 +730,14 @@ function generateReactLikeBaseComponent(typescript, framework) {
|
|
|
422
730
|
}
|
|
423
731
|
|
|
424
732
|
// src/generators/svelte.ts
|
|
425
|
-
function generateSvelteComponent(_componentName, iconNode, typescript) {
|
|
733
|
+
function generateSvelteComponent(_componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
426
734
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
427
735
|
const templatePath = getSvelteTemplatePath(typescript, "component");
|
|
428
736
|
return renderTemplate(templatePath, {
|
|
429
737
|
typescript,
|
|
430
|
-
formattedNodes
|
|
738
|
+
formattedNodes,
|
|
739
|
+
keepColors,
|
|
740
|
+
viewBox
|
|
431
741
|
});
|
|
432
742
|
}
|
|
433
743
|
function generateSvelteIcon(typescript) {
|
|
@@ -436,14 +746,15 @@ function generateSvelteIcon(typescript) {
|
|
|
436
746
|
}
|
|
437
747
|
|
|
438
748
|
// src/generators/vanilla.ts
|
|
439
|
-
function generateVanillaComponent(componentName, iconNode, typescript, keepColors) {
|
|
749
|
+
function generateVanillaComponent(componentName, iconNode, typescript, keepColors, viewBox) {
|
|
440
750
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 2)).join(",\n");
|
|
441
751
|
const templatePath = getVanillaTemplatePath(typescript, "component");
|
|
442
752
|
return renderTemplate(templatePath, {
|
|
443
753
|
componentName,
|
|
444
754
|
formattedNodes,
|
|
445
755
|
typescript,
|
|
446
|
-
keepColors
|
|
756
|
+
keepColors,
|
|
757
|
+
viewBox
|
|
447
758
|
});
|
|
448
759
|
}
|
|
449
760
|
function generateVanillaBaseComponent(typescript) {
|
|
@@ -455,13 +766,15 @@ function generateVanillaBaseComponent(typescript) {
|
|
|
455
766
|
}
|
|
456
767
|
|
|
457
768
|
// src/generators/vue.ts
|
|
458
|
-
function generateVueComponent(componentName, iconNode, typescript) {
|
|
769
|
+
function generateVueComponent(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
459
770
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
460
771
|
const templatePath = getVueTemplatePath(typescript, "component");
|
|
461
772
|
return renderTemplate(templatePath, {
|
|
462
773
|
typescript,
|
|
463
774
|
componentName,
|
|
464
|
-
formattedNodes
|
|
775
|
+
formattedNodes,
|
|
776
|
+
keepColors,
|
|
777
|
+
viewBox
|
|
465
778
|
});
|
|
466
779
|
}
|
|
467
780
|
function generateVueIcon(typescript) {
|
|
@@ -470,13 +783,15 @@ function generateVueIcon(typescript) {
|
|
|
470
783
|
}
|
|
471
784
|
|
|
472
785
|
// src/generators/vue2.ts
|
|
473
|
-
function generateVue2Component(componentName, iconNode, typescript) {
|
|
786
|
+
function generateVue2Component(componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") {
|
|
474
787
|
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
475
788
|
const templatePath = getVue2TemplatePath(typescript, "component");
|
|
476
789
|
return renderTemplate(templatePath, {
|
|
477
790
|
typescript,
|
|
478
791
|
componentName,
|
|
479
|
-
formattedNodes
|
|
792
|
+
formattedNodes,
|
|
793
|
+
keepColors,
|
|
794
|
+
viewBox
|
|
480
795
|
});
|
|
481
796
|
}
|
|
482
797
|
function generateVue2Icon(typescript) {
|
|
@@ -494,8 +809,8 @@ var ReactStrategy = class {
|
|
|
494
809
|
this.getIndexExtension = (typescript) => {
|
|
495
810
|
return typescript ? "ts" : "js";
|
|
496
811
|
};
|
|
497
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors = false) => {
|
|
498
|
-
return generateReactComponent(componentName, iconNode, typescript, keepColors);
|
|
812
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
813
|
+
return generateReactComponent(componentName, iconNode, typescript, keepColors, viewBox);
|
|
499
814
|
};
|
|
500
815
|
this.generateBaseComponent = (typescript) => {
|
|
501
816
|
return {
|
|
@@ -514,8 +829,8 @@ var VueStrategy = class {
|
|
|
514
829
|
this.getIndexExtension = (typescript) => {
|
|
515
830
|
return typescript ? "ts" : "js";
|
|
516
831
|
};
|
|
517
|
-
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
518
|
-
return generateVueComponent(componentName, iconNode, typescript);
|
|
832
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
833
|
+
return generateVueComponent(componentName, iconNode, typescript, keepColors, viewBox);
|
|
519
834
|
};
|
|
520
835
|
this.generateBaseComponent = (typescript) => {
|
|
521
836
|
return {
|
|
@@ -534,8 +849,8 @@ var Vue2Strategy = class {
|
|
|
534
849
|
this.getIndexExtension = (typescript) => {
|
|
535
850
|
return typescript ? "ts" : "js";
|
|
536
851
|
};
|
|
537
|
-
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
538
|
-
return generateVue2Component(componentName, iconNode, typescript);
|
|
852
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
853
|
+
return generateVue2Component(componentName, iconNode, typescript, keepColors, viewBox);
|
|
539
854
|
};
|
|
540
855
|
this.generateBaseComponent = (typescript) => {
|
|
541
856
|
return {
|
|
@@ -554,8 +869,8 @@ var SvelteStrategy = class {
|
|
|
554
869
|
this.getIndexExtension = (typescript) => {
|
|
555
870
|
return typescript ? "ts" : "js";
|
|
556
871
|
};
|
|
557
|
-
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
558
|
-
return generateSvelteComponent(componentName, iconNode, typescript);
|
|
872
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors = false, viewBox = "0 0 24 24") => {
|
|
873
|
+
return generateSvelteComponent(componentName, iconNode, typescript, keepColors, viewBox);
|
|
559
874
|
};
|
|
560
875
|
this.generateBaseComponent = (typescript) => {
|
|
561
876
|
return {
|
|
@@ -574,8 +889,8 @@ var SolidStrategy = class {
|
|
|
574
889
|
this.getIndexExtension = (typescript) => {
|
|
575
890
|
return typescript ? "ts" : "js";
|
|
576
891
|
};
|
|
577
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
578
|
-
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "solid");
|
|
892
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
893
|
+
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24", "solid");
|
|
579
894
|
};
|
|
580
895
|
this.generateBaseComponent = (typescript) => {
|
|
581
896
|
return generateReactLikeBaseComponent(typescript, "solid");
|
|
@@ -591,8 +906,8 @@ var PreactStrategy = class {
|
|
|
591
906
|
this.getIndexExtension = (typescript) => {
|
|
592
907
|
return typescript ? "ts" : "js";
|
|
593
908
|
};
|
|
594
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
595
|
-
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "preact");
|
|
909
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
910
|
+
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24", "preact");
|
|
596
911
|
};
|
|
597
912
|
this.generateBaseComponent = (typescript) => {
|
|
598
913
|
return generateReactLikeBaseComponent(typescript, "preact");
|
|
@@ -608,8 +923,8 @@ var VanillaStrategy = class {
|
|
|
608
923
|
this.getIndexExtension = (typescript) => {
|
|
609
924
|
return typescript ? "ts" : "js";
|
|
610
925
|
};
|
|
611
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
612
|
-
return generateVanillaComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
926
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
927
|
+
return generateVanillaComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
613
928
|
};
|
|
614
929
|
this.generateBaseComponent = (typescript) => {
|
|
615
930
|
return generateVanillaBaseComponent(typescript);
|
|
@@ -625,8 +940,8 @@ var LitStrategy = class {
|
|
|
625
940
|
this.getIndexExtension = (typescript) => {
|
|
626
941
|
return typescript ? "ts" : "js";
|
|
627
942
|
};
|
|
628
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
629
|
-
return generateLitComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
943
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
944
|
+
return generateLitComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
630
945
|
};
|
|
631
946
|
this.generateBaseComponent = (typescript) => {
|
|
632
947
|
return generateLitBaseComponent(typescript);
|
|
@@ -642,8 +957,8 @@ var QwikStrategy = class {
|
|
|
642
957
|
this.getIndexExtension = (typescript) => {
|
|
643
958
|
return typescript ? "ts" : "js";
|
|
644
959
|
};
|
|
645
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
646
|
-
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, "qwik");
|
|
960
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
961
|
+
return generateReactLikeComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24", "qwik");
|
|
647
962
|
};
|
|
648
963
|
this.generateBaseComponent = (typescript) => {
|
|
649
964
|
return generateReactLikeBaseComponent(typescript, "qwik");
|
|
@@ -659,8 +974,8 @@ var AstroStrategy = class {
|
|
|
659
974
|
this.getIndexExtension = (typescript) => {
|
|
660
975
|
return typescript ? "ts" : "js";
|
|
661
976
|
};
|
|
662
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
663
|
-
return generateAstroComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
977
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
978
|
+
return generateAstroComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
664
979
|
};
|
|
665
980
|
this.generateBaseComponent = (typescript) => {
|
|
666
981
|
return generateAstroBaseComponent(typescript);
|
|
@@ -676,8 +991,8 @@ var AngularStrategy = class {
|
|
|
676
991
|
this.getIndexExtension = (_typescript) => {
|
|
677
992
|
return "ts";
|
|
678
993
|
};
|
|
679
|
-
this.generateComponent = (componentName, iconNode, typescript, keepColors) => {
|
|
680
|
-
return generateAngularComponent(componentName, iconNode, typescript, keepColors ?? false);
|
|
994
|
+
this.generateComponent = (componentName, iconNode, typescript, keepColors, viewBox) => {
|
|
995
|
+
return generateAngularComponent(componentName, iconNode, typescript, keepColors ?? false, viewBox ?? "0 0 24 24");
|
|
681
996
|
};
|
|
682
997
|
this.generateBaseComponent = (typescript) => {
|
|
683
998
|
return generateAngularBaseComponent(typescript);
|
|
@@ -739,7 +1054,6 @@ var DEFAULT_CONFIG = {
|
|
|
739
1054
|
output: "./src/icons",
|
|
740
1055
|
typescript: true,
|
|
741
1056
|
optimize: true,
|
|
742
|
-
keepColors: false,
|
|
743
1057
|
prefix: "",
|
|
744
1058
|
suffix: "",
|
|
745
1059
|
configDir: ".",
|
|
@@ -756,8 +1070,8 @@ var DEFAULT_CONFIG = {
|
|
|
756
1070
|
}
|
|
757
1071
|
};
|
|
758
1072
|
async function loadConfig(configPath) {
|
|
759
|
-
const absolutePath =
|
|
760
|
-
const configDir =
|
|
1073
|
+
const absolutePath = import_node_path3.default.resolve(import_node_process.default.cwd(), configPath);
|
|
1074
|
+
const configDir = import_node_path3.default.dirname(absolutePath);
|
|
761
1075
|
const jiti = (0, import_jiti.createJiti)(configDir, {
|
|
762
1076
|
interopDefault: true
|
|
763
1077
|
});
|
|
@@ -784,12 +1098,12 @@ async function loadConfig(configPath) {
|
|
|
784
1098
|
}
|
|
785
1099
|
};
|
|
786
1100
|
if (mergedConfig.configDir && mergedConfig.configDir !== ".") {
|
|
787
|
-
const projectRoot =
|
|
788
|
-
mergedConfig.input =
|
|
789
|
-
mergedConfig.output =
|
|
1101
|
+
const projectRoot = import_node_path3.default.resolve(configDir, mergedConfig.configDir);
|
|
1102
|
+
mergedConfig.input = import_node_path3.default.resolve(projectRoot, mergedConfig.input);
|
|
1103
|
+
mergedConfig.output = import_node_path3.default.resolve(projectRoot, mergedConfig.output);
|
|
790
1104
|
} else {
|
|
791
|
-
mergedConfig.input =
|
|
792
|
-
mergedConfig.output =
|
|
1105
|
+
mergedConfig.input = import_node_path3.default.resolve(configDir, mergedConfig.input);
|
|
1106
|
+
mergedConfig.output = import_node_path3.default.resolve(configDir, mergedConfig.output);
|
|
793
1107
|
}
|
|
794
1108
|
if (!mergedConfig.framework) {
|
|
795
1109
|
const supported = frameworkRegistry.getSupportedFrameworks().join(", ");
|
|
@@ -808,7 +1122,7 @@ async function findConfig() {
|
|
|
808
1122
|
"vectify.config.js"
|
|
809
1123
|
];
|
|
810
1124
|
for (const file of configFiles) {
|
|
811
|
-
const configPath =
|
|
1125
|
+
const configPath = import_node_path3.default.resolve(import_node_process.default.cwd(), file);
|
|
812
1126
|
if (await fileExists2(configPath)) {
|
|
813
1127
|
return configPath;
|
|
814
1128
|
}
|
|
@@ -817,7 +1131,7 @@ async function findConfig() {
|
|
|
817
1131
|
}
|
|
818
1132
|
|
|
819
1133
|
// src/generators/index.ts
|
|
820
|
-
var
|
|
1134
|
+
var import_node_path5 = __toESM(require("path"));
|
|
821
1135
|
|
|
822
1136
|
// src/parsers/optimizer.ts
|
|
823
1137
|
var import_svgo = require("svgo");
|
|
@@ -853,7 +1167,7 @@ async function optimizeSvg(svgContent, config) {
|
|
|
853
1167
|
|
|
854
1168
|
// src/utils/formatter.ts
|
|
855
1169
|
var import_node_child_process = require("child_process");
|
|
856
|
-
var
|
|
1170
|
+
var import_node_path4 = __toESM(require("path"));
|
|
857
1171
|
var import_node_process2 = __toESM(require("process"));
|
|
858
1172
|
var import_node_util = require("util");
|
|
859
1173
|
init_helpers();
|
|
@@ -908,7 +1222,7 @@ async function detectFormatter() {
|
|
|
908
1222
|
for (const tool of priority) {
|
|
909
1223
|
const patterns = FORMATTER_PATTERNS[tool];
|
|
910
1224
|
for (const pattern of patterns) {
|
|
911
|
-
const configPath =
|
|
1225
|
+
const configPath = import_node_path4.default.join(cwd, pattern);
|
|
912
1226
|
if (await fileExists(configPath)) {
|
|
913
1227
|
return tool;
|
|
914
1228
|
}
|
|
@@ -1004,90 +1318,206 @@ async function generateIcons(config, dryRun = false) {
|
|
|
1004
1318
|
}
|
|
1005
1319
|
return stats;
|
|
1006
1320
|
}
|
|
1007
|
-
async function
|
|
1008
|
-
|
|
1009
|
-
|
|
1321
|
+
async function generateIconsIncremental(config, cacheManager, dryRun = false) {
|
|
1322
|
+
const stats = {
|
|
1323
|
+
success: 0,
|
|
1324
|
+
failed: 0,
|
|
1325
|
+
total: 0,
|
|
1326
|
+
errors: []
|
|
1327
|
+
};
|
|
1328
|
+
try {
|
|
1329
|
+
if (!dryRun) {
|
|
1330
|
+
await ensureDir(config.output);
|
|
1331
|
+
}
|
|
1332
|
+
const svgFiles = await getSvgFiles(config.input);
|
|
1333
|
+
stats.total = svgFiles.length;
|
|
1334
|
+
if (svgFiles.length === 0) {
|
|
1335
|
+
console.warn(`No SVG files found in ${config.input}`);
|
|
1336
|
+
return stats;
|
|
1337
|
+
}
|
|
1338
|
+
if (cacheManager.hasConfigChanged(config)) {
|
|
1339
|
+
console.log("\u26A0\uFE0F Configuration changed, rebuilding all icons...");
|
|
1340
|
+
cacheManager.invalidateAll();
|
|
1341
|
+
}
|
|
1342
|
+
cacheManager.updateConfigHash(config);
|
|
1343
|
+
await cacheManager.cleanStaleEntries(svgFiles);
|
|
1344
|
+
if (config.generateOptions?.cleanOutput && !dryRun) {
|
|
1345
|
+
await cleanOutputDirectory(svgFiles, config);
|
|
1346
|
+
}
|
|
1347
|
+
await generateBaseComponent(config, dryRun);
|
|
1348
|
+
const strategy = getFrameworkStrategy(config.framework);
|
|
1349
|
+
const typescript = config.typescript ?? true;
|
|
1350
|
+
const fileExt = strategy.getComponentExtension(typescript);
|
|
1351
|
+
const filesToGenerate = [];
|
|
1352
|
+
const cachedFiles = [];
|
|
1353
|
+
for (const svgFile of svgFiles) {
|
|
1354
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1355
|
+
const componentName = getComponentName(
|
|
1356
|
+
fileName,
|
|
1357
|
+
config.prefix,
|
|
1358
|
+
config.suffix,
|
|
1359
|
+
config.componentNameTransform
|
|
1360
|
+
);
|
|
1361
|
+
const componentPath = import_node_path5.default.join(config.output, `${componentName}.${fileExt}`);
|
|
1362
|
+
const needsRegen = await cacheManager.needsRegeneration(
|
|
1363
|
+
svgFile,
|
|
1364
|
+
componentPath,
|
|
1365
|
+
config
|
|
1366
|
+
);
|
|
1367
|
+
if (needsRegen) {
|
|
1368
|
+
filesToGenerate.push(svgFile);
|
|
1369
|
+
} else {
|
|
1370
|
+
cachedFiles.push(svgFile);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
if (cachedFiles.length > 0) {
|
|
1374
|
+
console.log(`\u{1F4E6} Cache: ${cachedFiles.length} cached, ${filesToGenerate.length} to generate`);
|
|
1375
|
+
}
|
|
1376
|
+
for (const svgFile of filesToGenerate) {
|
|
1377
|
+
try {
|
|
1378
|
+
await generateIconComponent(svgFile, config, dryRun, cacheManager);
|
|
1379
|
+
stats.success++;
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
stats.failed++;
|
|
1382
|
+
stats.errors.push({
|
|
1383
|
+
file: svgFile,
|
|
1384
|
+
error: error.message
|
|
1385
|
+
});
|
|
1386
|
+
console.error(`Failed to generate ${svgFile}: ${error.message}`);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
stats.success += cachedFiles.length;
|
|
1390
|
+
if (config.generateOptions?.index) {
|
|
1391
|
+
await generateIndexFile(svgFiles, config, dryRun);
|
|
1392
|
+
}
|
|
1393
|
+
if (config.generateOptions?.preview && !dryRun) {
|
|
1394
|
+
await generatePreviewHtml(svgFiles, config);
|
|
1395
|
+
}
|
|
1396
|
+
if (!dryRun) {
|
|
1397
|
+
await cacheManager.save();
|
|
1398
|
+
const cacheStats = cacheManager.getStats();
|
|
1399
|
+
if (cacheStats.total > 0) {
|
|
1400
|
+
const hitRate = cacheManager.getHitRate();
|
|
1401
|
+
const timeSaved = (cacheStats.timeSaved / 1e3).toFixed(1);
|
|
1402
|
+
console.log(`\u26A1 Cache saved ~${timeSaved}s (${hitRate.toFixed(1)}% hit rate)`);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
if (config.format && !dryRun) {
|
|
1406
|
+
const formatResult = await formatOutput(config.output, config.format);
|
|
1407
|
+
if (formatResult.success && formatResult.tool) {
|
|
1408
|
+
console.log(`Formatted with ${formatResult.tool}`);
|
|
1409
|
+
} else if (formatResult.error) {
|
|
1410
|
+
console.warn(formatResult.error);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
if (config.hooks?.onComplete) {
|
|
1414
|
+
await config.hooks.onComplete(stats);
|
|
1415
|
+
}
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
throw new Error(`Generation failed: ${error.message}`);
|
|
1418
|
+
}
|
|
1419
|
+
return stats;
|
|
1420
|
+
}
|
|
1421
|
+
async function generateIconComponent(svgFile, config, dryRun = false, cacheManager) {
|
|
1422
|
+
let svgContent = await readFile3(svgFile);
|
|
1423
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1010
1424
|
if (config.hooks?.beforeParse) {
|
|
1011
1425
|
svgContent = await config.hooks.beforeParse(svgContent, fileName);
|
|
1012
1426
|
}
|
|
1427
|
+
const { isMultiColor: isMultiColorBeforeOptimization } = parseSvg(svgContent);
|
|
1013
1428
|
svgContent = await optimizeSvg(svgContent, config);
|
|
1014
|
-
const
|
|
1429
|
+
const { iconNodes, viewBox } = parseSvg(svgContent);
|
|
1015
1430
|
const componentName = getComponentName(
|
|
1016
1431
|
fileName,
|
|
1017
1432
|
config.prefix,
|
|
1018
1433
|
config.suffix,
|
|
1019
|
-
config.
|
|
1434
|
+
config.componentNameTransform
|
|
1020
1435
|
);
|
|
1021
1436
|
const strategy = getFrameworkStrategy(config.framework);
|
|
1022
1437
|
const typescript = config.typescript ?? true;
|
|
1438
|
+
const keepColors = config.keepColors !== void 0 ? config.keepColors : isMultiColorBeforeOptimization;
|
|
1023
1439
|
let code = strategy.generateComponent(
|
|
1024
1440
|
componentName,
|
|
1025
|
-
|
|
1441
|
+
iconNodes,
|
|
1026
1442
|
typescript,
|
|
1027
|
-
|
|
1443
|
+
keepColors,
|
|
1444
|
+
viewBox
|
|
1028
1445
|
);
|
|
1029
1446
|
if (config.hooks?.afterGenerate) {
|
|
1030
1447
|
code = await config.hooks.afterGenerate(code, componentName);
|
|
1031
1448
|
}
|
|
1032
1449
|
const fileExt = strategy.getComponentExtension(typescript);
|
|
1033
|
-
const outputPath =
|
|
1450
|
+
const outputPath = import_node_path5.default.join(config.output, `${componentName}.${fileExt}`);
|
|
1034
1451
|
if (dryRun) {
|
|
1035
1452
|
console.log(` ${componentName}.${fileExt}`);
|
|
1036
1453
|
} else {
|
|
1037
|
-
await
|
|
1454
|
+
await writeFile2(outputPath, code);
|
|
1455
|
+
if (cacheManager) {
|
|
1456
|
+
const componentHash = hashContent(code);
|
|
1457
|
+
await cacheManager.updateEntry(
|
|
1458
|
+
svgFile,
|
|
1459
|
+
outputPath,
|
|
1460
|
+
componentName,
|
|
1461
|
+
componentHash,
|
|
1462
|
+
config
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1038
1465
|
}
|
|
1039
1466
|
}
|
|
1040
1467
|
async function generateBaseComponent(config, dryRun = false) {
|
|
1041
1468
|
const typescript = config.typescript ?? true;
|
|
1042
1469
|
const strategy = getFrameworkStrategy(config.framework);
|
|
1043
1470
|
const { code, fileName } = strategy.generateBaseComponent(typescript);
|
|
1044
|
-
const outputPath =
|
|
1471
|
+
const outputPath = import_node_path5.default.join(config.output, fileName);
|
|
1045
1472
|
if (dryRun) {
|
|
1046
1473
|
console.log(` ${fileName}`);
|
|
1047
1474
|
} else {
|
|
1048
|
-
await
|
|
1475
|
+
await writeFile2(outputPath, code);
|
|
1049
1476
|
}
|
|
1050
1477
|
}
|
|
1051
1478
|
async function generateIndexFile(svgFiles, config, dryRun = false) {
|
|
1052
1479
|
const typescript = config.typescript ?? true;
|
|
1053
1480
|
const strategy = getFrameworkStrategy(config.framework);
|
|
1054
1481
|
const ext = strategy.getIndexExtension(typescript);
|
|
1482
|
+
const componentExt = strategy.getComponentExtension(typescript);
|
|
1055
1483
|
const usesDefaultExport = ["vue", "vue2", "svelte", "react", "preact"].includes(config.framework);
|
|
1484
|
+
const needsExtension = ["vue", "vue2", "svelte"].includes(config.framework);
|
|
1056
1485
|
const exports2 = svgFiles.map((svgFile) => {
|
|
1057
|
-
const fileName =
|
|
1486
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1058
1487
|
const componentName = getComponentName(
|
|
1059
1488
|
fileName,
|
|
1060
1489
|
config.prefix,
|
|
1061
1490
|
config.suffix,
|
|
1062
|
-
config.
|
|
1491
|
+
config.componentNameTransform
|
|
1063
1492
|
);
|
|
1493
|
+
const importPath = needsExtension ? `./${componentName}.${componentExt}` : `./${componentName}`;
|
|
1064
1494
|
if (usesDefaultExport) {
|
|
1065
|
-
return `export { default as ${componentName} } from '
|
|
1495
|
+
return `export { default as ${componentName} } from '${importPath}'`;
|
|
1066
1496
|
} else {
|
|
1067
|
-
return `export { ${componentName} } from '
|
|
1497
|
+
return `export { ${componentName} } from '${importPath}'`;
|
|
1068
1498
|
}
|
|
1069
1499
|
}).join("\n");
|
|
1070
|
-
const indexPath =
|
|
1500
|
+
const indexPath = import_node_path5.default.join(config.output, `index.${ext}`);
|
|
1071
1501
|
if (dryRun) {
|
|
1072
1502
|
console.log(` index.${ext}`);
|
|
1073
1503
|
} else {
|
|
1074
|
-
await
|
|
1504
|
+
await writeFile2(indexPath, `${exports2}
|
|
1075
1505
|
`);
|
|
1076
1506
|
}
|
|
1077
1507
|
}
|
|
1078
1508
|
async function generatePreviewHtml(svgFiles, config) {
|
|
1079
1509
|
const componentNames = svgFiles.map((svgFile) => {
|
|
1080
|
-
const fileName =
|
|
1510
|
+
const fileName = import_node_path5.default.basename(svgFile);
|
|
1081
1511
|
return getComponentName(
|
|
1082
1512
|
fileName,
|
|
1083
1513
|
config.prefix,
|
|
1084
1514
|
config.suffix,
|
|
1085
|
-
config.
|
|
1515
|
+
config.componentNameTransform
|
|
1086
1516
|
);
|
|
1087
1517
|
});
|
|
1088
1518
|
const svgContents = await Promise.all(
|
|
1089
1519
|
svgFiles.map(async (svgFile) => {
|
|
1090
|
-
return await
|
|
1520
|
+
return await readFile3(svgFile);
|
|
1091
1521
|
})
|
|
1092
1522
|
);
|
|
1093
1523
|
const html = `<!DOCTYPE html>
|
|
@@ -1249,8 +1679,8 @@ async function generatePreviewHtml(svgFiles, config) {
|
|
|
1249
1679
|
</script>
|
|
1250
1680
|
</body>
|
|
1251
1681
|
</html>`;
|
|
1252
|
-
const previewPath =
|
|
1253
|
-
await
|
|
1682
|
+
const previewPath = import_node_path5.default.join(config.output, "preview.html");
|
|
1683
|
+
await writeFile2(previewPath, html);
|
|
1254
1684
|
}
|
|
1255
1685
|
async function cleanOutputDirectory(svgFiles, config) {
|
|
1256
1686
|
const { readdir, unlink } = await import("fs/promises");
|
|
@@ -1258,12 +1688,12 @@ async function cleanOutputDirectory(svgFiles, config) {
|
|
|
1258
1688
|
const fileExt = strategy.getComponentExtension(config.typescript ?? true);
|
|
1259
1689
|
const expectedComponents = new Set(
|
|
1260
1690
|
svgFiles.map((svgFile) => {
|
|
1261
|
-
const fileName =
|
|
1691
|
+
const fileName = import_node_path5.default.basename(svgFile, ".svg");
|
|
1262
1692
|
const componentName = getComponentName(
|
|
1263
1693
|
fileName,
|
|
1264
1694
|
config.prefix,
|
|
1265
1695
|
config.suffix,
|
|
1266
|
-
config.
|
|
1696
|
+
config.componentNameTransform
|
|
1267
1697
|
);
|
|
1268
1698
|
return `${componentName}.${fileExt}`;
|
|
1269
1699
|
})
|
|
@@ -1285,7 +1715,7 @@ async function cleanOutputDirectory(svgFiles, config) {
|
|
|
1285
1715
|
continue;
|
|
1286
1716
|
}
|
|
1287
1717
|
if (!expectedComponents.has(file)) {
|
|
1288
|
-
const filePath =
|
|
1718
|
+
const filePath = import_node_path5.default.join(config.output, file);
|
|
1289
1719
|
await unlink(filePath);
|
|
1290
1720
|
console.log(`Deleted orphaned component: ${file}`);
|
|
1291
1721
|
}
|
|
@@ -1317,9 +1747,19 @@ async function generate(options = {}) {
|
|
|
1317
1747
|
${import_chalk.default.bold("Files that would be generated:")}
|
|
1318
1748
|
`);
|
|
1319
1749
|
}
|
|
1750
|
+
const useIncremental = config.incremental?.enabled !== false && !options.force && !options.dryRun;
|
|
1751
|
+
let cacheManager = null;
|
|
1752
|
+
if (useIncremental) {
|
|
1753
|
+
const cacheDir = config.incremental?.cacheDir || ".vectify";
|
|
1754
|
+
cacheManager = new CacheManager(config.output, cacheDir);
|
|
1755
|
+
await cacheManager.load();
|
|
1756
|
+
}
|
|
1757
|
+
if (options.force) {
|
|
1758
|
+
spinner.info(import_chalk.default.yellow("Force mode - ignoring cache, regenerating all icons"));
|
|
1759
|
+
}
|
|
1320
1760
|
const actionText = options.dryRun ? "Analyzing icons..." : "Generating icon components...";
|
|
1321
1761
|
spinner.start(actionText);
|
|
1322
|
-
const stats = await generateIcons(config, options.dryRun);
|
|
1762
|
+
const stats = cacheManager ? await generateIconsIncremental(config, cacheManager, options.dryRun) : await generateIcons(config, options.dryRun);
|
|
1323
1763
|
if (stats.failed > 0) {
|
|
1324
1764
|
spinner.warn(`${options.dryRun ? "Analyzed" : "Generated"} ${import_chalk.default.green(stats.success)} icons, ${import_chalk.default.red(stats.failed)} failed`);
|
|
1325
1765
|
if (stats.errors.length > 0) {
|
|
@@ -1352,7 +1792,7 @@ ${import_chalk.default.bold("Output:")} ${import_chalk.default.cyan(config.outpu
|
|
|
1352
1792
|
}
|
|
1353
1793
|
|
|
1354
1794
|
// src/commands/init.ts
|
|
1355
|
-
var
|
|
1795
|
+
var import_node_path6 = __toESM(require("path"));
|
|
1356
1796
|
var import_node_process3 = __toESM(require("process"));
|
|
1357
1797
|
var import_chalk2 = __toESM(require("chalk"));
|
|
1358
1798
|
var import_inquirer = __toESM(require("inquirer"));
|
|
@@ -1382,8 +1822,8 @@ Note: Project root detected at ${import_chalk2.default.cyan(projectRoot)}`));
|
|
|
1382
1822
|
}
|
|
1383
1823
|
}
|
|
1384
1824
|
]);
|
|
1385
|
-
const configPath =
|
|
1386
|
-
const configDir =
|
|
1825
|
+
const configPath = import_node_path6.default.resolve(projectRoot, pathAnswers.configPath);
|
|
1826
|
+
const configDir = import_node_path6.default.dirname(configPath);
|
|
1387
1827
|
if (!options.force && await fileExists(configPath)) {
|
|
1388
1828
|
const { overwrite } = await import_inquirer.default.prompt([
|
|
1389
1829
|
{
|
|
@@ -1457,18 +1897,18 @@ Note: Project root detected at ${import_chalk2.default.cyan(projectRoot)}`));
|
|
|
1457
1897
|
default: ""
|
|
1458
1898
|
}
|
|
1459
1899
|
]);
|
|
1460
|
-
const inputPath =
|
|
1461
|
-
const outputPath =
|
|
1900
|
+
const inputPath = import_node_path6.default.resolve(projectRoot, answers.input);
|
|
1901
|
+
const outputPath = import_node_path6.default.resolve(projectRoot, answers.output);
|
|
1462
1902
|
const spinner = (0, import_ora2.default)("Setting up directories...").start();
|
|
1463
1903
|
await ensureDir(inputPath);
|
|
1464
1904
|
spinner.text = `Created input directory: ${import_chalk2.default.cyan(answers.input)}`;
|
|
1465
1905
|
await ensureDir(outputPath);
|
|
1466
1906
|
spinner.succeed(`Created output directory: ${import_chalk2.default.cyan(answers.output)}`);
|
|
1467
|
-
const relativeConfigDir =
|
|
1907
|
+
const relativeConfigDir = import_node_path6.default.relative(configDir, projectRoot) || ".";
|
|
1468
1908
|
const finalFramework = answers.vueVersion || answers.framework;
|
|
1469
1909
|
const configContent = generateConfigContent({ ...answers, framework: finalFramework }, relativeConfigDir);
|
|
1470
1910
|
spinner.start("Creating config file...");
|
|
1471
|
-
await
|
|
1911
|
+
await writeFile2(configPath, configContent);
|
|
1472
1912
|
spinner.succeed(`Config file created at ${import_chalk2.default.green(configPath)}`);
|
|
1473
1913
|
console.log(`
|
|
1474
1914
|
${import_chalk2.default.bold("Next steps:")}`);
|
|
@@ -1508,10 +1948,93 @@ export default defineConfig({
|
|
|
1508
1948
|
}
|
|
1509
1949
|
|
|
1510
1950
|
// src/commands/watch.ts
|
|
1511
|
-
var
|
|
1951
|
+
var import_node_path7 = __toESM(require("path"));
|
|
1512
1952
|
var import_chalk3 = __toESM(require("chalk"));
|
|
1513
1953
|
var import_chokidar = __toESM(require("chokidar"));
|
|
1514
1954
|
var import_ora3 = __toESM(require("ora"));
|
|
1955
|
+
|
|
1956
|
+
// src/cache/svg-validator.ts
|
|
1957
|
+
var import_promises3 = require("fs/promises");
|
|
1958
|
+
var import_cheerio = require("cheerio");
|
|
1959
|
+
var MIN_SVG_SIZE = 20;
|
|
1960
|
+
var DRAWABLE_ELEMENTS = [
|
|
1961
|
+
"path",
|
|
1962
|
+
"circle",
|
|
1963
|
+
"rect",
|
|
1964
|
+
"ellipse",
|
|
1965
|
+
"line",
|
|
1966
|
+
"polyline",
|
|
1967
|
+
"polygon",
|
|
1968
|
+
"text",
|
|
1969
|
+
"image",
|
|
1970
|
+
"use"
|
|
1971
|
+
];
|
|
1972
|
+
async function validateSVGFile(filePath) {
|
|
1973
|
+
try {
|
|
1974
|
+
const stats = await (0, import_promises3.stat)(filePath);
|
|
1975
|
+
if (stats.size < MIN_SVG_SIZE) {
|
|
1976
|
+
return {
|
|
1977
|
+
isValid: false,
|
|
1978
|
+
isEmpty: true,
|
|
1979
|
+
reason: "File is too small to be a valid SVG"
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
const content = await (0, import_promises3.readFile)(filePath, "utf-8");
|
|
1983
|
+
if (!content.trim()) {
|
|
1984
|
+
return {
|
|
1985
|
+
isValid: false,
|
|
1986
|
+
isEmpty: true,
|
|
1987
|
+
reason: "File is empty"
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
if (!content.includes("<svg")) {
|
|
1991
|
+
return {
|
|
1992
|
+
isValid: false,
|
|
1993
|
+
isEmpty: false,
|
|
1994
|
+
reason: "File does not contain <svg> tag"
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1997
|
+
if (!hasDrawableContent(content)) {
|
|
1998
|
+
return {
|
|
1999
|
+
isValid: false,
|
|
2000
|
+
isEmpty: true,
|
|
2001
|
+
reason: "SVG has no drawable content"
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
try {
|
|
2005
|
+
const $ = (0, import_cheerio.load)(content, { xmlMode: true });
|
|
2006
|
+
const svgElement = $("svg");
|
|
2007
|
+
if (svgElement.length === 0) {
|
|
2008
|
+
return {
|
|
2009
|
+
isValid: false,
|
|
2010
|
+
isEmpty: false,
|
|
2011
|
+
reason: "Failed to parse SVG element"
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
return {
|
|
2015
|
+
isValid: true,
|
|
2016
|
+
isEmpty: false
|
|
2017
|
+
};
|
|
2018
|
+
} catch (parseError) {
|
|
2019
|
+
return {
|
|
2020
|
+
isValid: false,
|
|
2021
|
+
isEmpty: false,
|
|
2022
|
+
reason: `Failed to parse SVG: ${parseError}`
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
} catch (error) {
|
|
2026
|
+
return {
|
|
2027
|
+
isValid: false,
|
|
2028
|
+
isEmpty: false,
|
|
2029
|
+
reason: `Failed to read file: ${error}`
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
function hasDrawableContent(content) {
|
|
2034
|
+
return DRAWABLE_ELEMENTS.some((element) => content.includes(`<${element}`));
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
// src/commands/watch.ts
|
|
1515
2038
|
async function watch(options = {}) {
|
|
1516
2039
|
const spinner = (0, import_ora3.default)("Loading configuration...").start();
|
|
1517
2040
|
try {
|
|
@@ -1527,16 +2050,24 @@ async function watch(options = {}) {
|
|
|
1527
2050
|
}
|
|
1528
2051
|
const config = await loadConfig(configPath);
|
|
1529
2052
|
spinner.succeed(`Config loaded from ${import_chalk3.default.green(configPath)}`);
|
|
2053
|
+
const useIncremental = config.incremental?.enabled !== false;
|
|
2054
|
+
const cacheDir = config.incremental?.cacheDir || ".vectify";
|
|
2055
|
+
const cacheManager = useIncremental ? new CacheManager(config.output, cacheDir) : null;
|
|
2056
|
+
if (cacheManager) {
|
|
2057
|
+
await cacheManager.load();
|
|
2058
|
+
}
|
|
1530
2059
|
spinner.start("Generating icon components...");
|
|
1531
|
-
const initialStats = await generateIcons(config);
|
|
2060
|
+
const initialStats = useIncremental && cacheManager ? await generateIconsIncremental(config, cacheManager) : await generateIcons(config);
|
|
1532
2061
|
spinner.succeed(`Generated ${import_chalk3.default.green(initialStats.success)} icon components`);
|
|
1533
|
-
const watchPath =
|
|
2062
|
+
const watchPath = import_node_path7.default.join(config.input, "**/*.svg");
|
|
1534
2063
|
const debounce = config.watch?.debounce ?? 300;
|
|
1535
2064
|
const ignore = config.watch?.ignore ?? ["**/node_modules/**", "**/.git/**"];
|
|
2065
|
+
const emptyFileRetryDelay = config.watch?.emptyFileRetryDelay ?? 2e3;
|
|
1536
2066
|
console.log(import_chalk3.default.bold("\nWatching for changes..."));
|
|
1537
2067
|
console.log(` ${import_chalk3.default.cyan(watchPath)}`);
|
|
1538
2068
|
console.log(` ${import_chalk3.default.gray("Press Ctrl+C to stop")}
|
|
1539
2069
|
`);
|
|
2070
|
+
const pendingChanges = /* @__PURE__ */ new Map();
|
|
1540
2071
|
const debounceTimer = null;
|
|
1541
2072
|
const watcher = import_chokidar.default.watch(watchPath, {
|
|
1542
2073
|
ignored: ignore,
|
|
@@ -1544,12 +2075,12 @@ async function watch(options = {}) {
|
|
|
1544
2075
|
ignoreInitial: true
|
|
1545
2076
|
});
|
|
1546
2077
|
watcher.on("add", (filePath) => {
|
|
1547
|
-
handleChange("added", filePath, config, debounce, debounceTimer);
|
|
2078
|
+
handleChange("added", filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, debounceTimer);
|
|
1548
2079
|
}).on("change", (filePath) => {
|
|
1549
|
-
handleChange("changed", filePath, config, debounce, debounceTimer);
|
|
2080
|
+
handleChange("changed", filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, debounceTimer);
|
|
1550
2081
|
}).on("unlink", (filePath) => {
|
|
1551
|
-
console.log(import_chalk3.default.yellow(`SVG file removed: ${
|
|
1552
|
-
handleChange("removed", filePath, config, debounce, debounceTimer);
|
|
2082
|
+
console.log(import_chalk3.default.yellow(`SVG file removed: ${import_node_path7.default.basename(filePath)}`));
|
|
2083
|
+
handleChange("removed", filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, debounceTimer);
|
|
1553
2084
|
}).on("error", (error) => {
|
|
1554
2085
|
console.error(import_chalk3.default.red(`Watcher error: ${error.message}`));
|
|
1555
2086
|
});
|
|
@@ -1566,23 +2097,51 @@ ${import_chalk3.default.yellow("Stopping watch mode...")}`);
|
|
|
1566
2097
|
throw error;
|
|
1567
2098
|
}
|
|
1568
2099
|
}
|
|
1569
|
-
function handleChange(event, filePath, config, debounce, timer) {
|
|
1570
|
-
|
|
2100
|
+
function handleChange(event, filePath, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, timer) {
|
|
2101
|
+
pendingChanges.set(filePath, event);
|
|
1571
2102
|
if (timer) {
|
|
1572
2103
|
clearTimeout(timer);
|
|
1573
2104
|
}
|
|
1574
2105
|
timer = setTimeout(async () => {
|
|
1575
|
-
const
|
|
2106
|
+
const changes = Array.from(pendingChanges.entries());
|
|
2107
|
+
pendingChanges.clear();
|
|
2108
|
+
const validChanges = [];
|
|
2109
|
+
const invalidFiles = [];
|
|
2110
|
+
for (const [file, changeEvent] of changes) {
|
|
2111
|
+
if (changeEvent === "removed") {
|
|
2112
|
+
validChanges.push([file, changeEvent]);
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
const validation = await validateSVGFile(file);
|
|
2116
|
+
if (!validation.isValid) {
|
|
2117
|
+
if (validation.isEmpty) {
|
|
2118
|
+
console.log(import_chalk3.default.yellow(`\u23F3 Waiting for content: ${import_node_path7.default.basename(file)}`));
|
|
2119
|
+
setTimeout(() => {
|
|
2120
|
+
handleChange(changeEvent, file, config, cacheManager, debounce, emptyFileRetryDelay, pendingChanges, timer);
|
|
2121
|
+
}, emptyFileRetryDelay);
|
|
2122
|
+
} else {
|
|
2123
|
+
console.error(import_chalk3.default.red(`\u274C Invalid SVG: ${import_node_path7.default.basename(file)} - ${validation.reason}`));
|
|
2124
|
+
invalidFiles.push(file);
|
|
2125
|
+
}
|
|
2126
|
+
continue;
|
|
2127
|
+
}
|
|
2128
|
+
validChanges.push([file, changeEvent]);
|
|
2129
|
+
}
|
|
2130
|
+
if (validChanges.length === 0) {
|
|
2131
|
+
return;
|
|
2132
|
+
}
|
|
2133
|
+
const spinner = (0, import_ora3.default)(`Processing ${validChanges.length} change(s)...`).start();
|
|
1576
2134
|
try {
|
|
1577
|
-
const stats = await generateIcons(config);
|
|
2135
|
+
const stats = cacheManager ? await generateIconsIncremental(config, cacheManager) : await generateIcons(config);
|
|
1578
2136
|
if (stats.failed > 0) {
|
|
1579
2137
|
spinner.warn(
|
|
1580
2138
|
`Regenerated ${import_chalk3.default.green(stats.success)} icons, ${import_chalk3.default.red(stats.failed)} failed`
|
|
1581
2139
|
);
|
|
1582
2140
|
} else {
|
|
1583
|
-
spinner.succeed(
|
|
2141
|
+
spinner.succeed(`\u2713 Updated ${import_chalk3.default.green(stats.success)} icon components`);
|
|
1584
2142
|
}
|
|
1585
|
-
|
|
2143
|
+
const triggerFiles = validChanges.map(([file, evt]) => `${import_node_path7.default.basename(file)} (${evt})`).join(", ");
|
|
2144
|
+
console.log(import_chalk3.default.gray(` Triggered by: ${triggerFiles}
|
|
1586
2145
|
`));
|
|
1587
2146
|
} catch (error) {
|
|
1588
2147
|
spinner.fail("Regeneration failed");
|
|
@@ -1596,13 +2155,13 @@ var import_meta2 = {};
|
|
|
1596
2155
|
function getPackageJson() {
|
|
1597
2156
|
let pkgPath;
|
|
1598
2157
|
if (typeof __dirname !== "undefined") {
|
|
1599
|
-
pkgPath = (0,
|
|
2158
|
+
pkgPath = (0, import_node_path8.join)(__dirname, "../package.json");
|
|
1600
2159
|
} else {
|
|
1601
2160
|
const __filename = (0, import_node_url2.fileURLToPath)(import_meta2.url);
|
|
1602
|
-
const __dirname2 = (0,
|
|
1603
|
-
pkgPath = (0,
|
|
2161
|
+
const __dirname2 = (0, import_node_path8.dirname)(__filename);
|
|
2162
|
+
pkgPath = (0, import_node_path8.join)(__dirname2, "../package.json");
|
|
1604
2163
|
}
|
|
1605
|
-
return JSON.parse((0,
|
|
2164
|
+
return JSON.parse((0, import_node_fs3.readFileSync)(pkgPath, "utf-8"));
|
|
1606
2165
|
}
|
|
1607
2166
|
var packageJson = getPackageJson();
|
|
1608
2167
|
var program = new import_commander.Command();
|
|
@@ -1615,7 +2174,7 @@ program.command("init").description("Initialize a new configuration file").optio
|
|
|
1615
2174
|
process.exit(1);
|
|
1616
2175
|
}
|
|
1617
2176
|
});
|
|
1618
|
-
program.command("generate").description("Generate icon components from SVG files").option("-c, --config <path>", "Path to config file").option("--dry-run", "Preview what will be generated without writing files").action(async (options) => {
|
|
2177
|
+
program.command("generate").description("Generate icon components from SVG files").option("-c, --config <path>", "Path to config file").option("--dry-run", "Preview what will be generated without writing files").option("--force", "Force full regeneration, ignoring cache").action(async (options) => {
|
|
1619
2178
|
try {
|
|
1620
2179
|
await generate(options);
|
|
1621
2180
|
} catch (error) {
|