vectify 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/README.zh-CN.md +67 -0
- package/dist/{chunk-F3AM6WVC.mjs → chunk-BKDGWTE6.mjs} +176 -23
- package/dist/cli.js +186 -32
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +182 -28
- package/dist/index.mjs +1 -1
- package/dist/templates/template-engine.ts +8 -0
- package/dist/templates/vue2/component.js.vue.hbs +20 -0
- package/dist/templates/vue2/component.ts.vue.hbs +22 -0
- package/dist/templates/vue2/icon.js.vue.hbs +135 -0
- package/dist/templates/vue2/icon.ts.vue.hbs +138 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ English | [简体中文](./README.zh-CN.md)
|
|
|
20
20
|
- [Configuration](#configuration)
|
|
21
21
|
- [Basic Options](#basic-options)
|
|
22
22
|
- [Generation Options](#generation-options)
|
|
23
|
+
- [Auto Formatting](#auto-formatting)
|
|
23
24
|
- [Watch Mode](#watch-mode)
|
|
24
25
|
- [SVGO Configuration](#svgo-configuration)
|
|
25
26
|
- [Lifecycle Hooks](#lifecycle-hooks)
|
|
@@ -185,6 +186,7 @@ All available options for `defineConfig()` are documented in the tables below.
|
|
|
185
186
|
| `prefix` | `string` | `''` | ❌ | Prefix added to all component names. Useful for namespacing. | `prefix: 'Icon'` → `IconArrowRight` |
|
|
186
187
|
| `suffix` | `string` | `''` | ❌ | Suffix added to all component names. | `suffix: 'Icon'` → `ArrowRightIcon` |
|
|
187
188
|
| `transform` | `(name: string) => string` | - | ❌ | Custom function to transform SVG filename to component name. Overrides default PascalCase conversion and prefix/suffix. | `transform: (n) => 'X' + n` |
|
|
189
|
+
| `format` | `boolean` \| `'prettier'` \| `'eslint'` \| `'biome'` \| `FormatConfig` | `false` | ❌ | Auto-format generated files after generation. See [Auto Formatting](#auto-formatting) for details. | `format: true` |
|
|
188
190
|
|
|
189
191
|
#### `generateOptions` Object
|
|
190
192
|
|
|
@@ -195,6 +197,71 @@ All available options for `defineConfig()` are documented in the tables below.
|
|
|
195
197
|
| `preview` | `boolean` | `false` | Generate interactive `preview.html` for browsing all icons locally. Useful for design review. | `preview: true` |
|
|
196
198
|
| `cleanOutput` | `boolean` | `false` | Remove orphaned component files that no longer have corresponding SVG files. Helps keep output directory clean. | `cleanOutput: true` |
|
|
197
199
|
|
|
200
|
+
#### Auto Formatting
|
|
201
|
+
|
|
202
|
+
Vectify can automatically format generated files using your project's formatter. This ensures generated code matches your project's code style.
|
|
203
|
+
|
|
204
|
+
**Quick Start:**
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
export default defineConfig({
|
|
208
|
+
framework: 'react',
|
|
209
|
+
input: './icons',
|
|
210
|
+
output: './src/icons',
|
|
211
|
+
format: true, // Auto-detect and use project formatter
|
|
212
|
+
})
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Format Options:**
|
|
216
|
+
|
|
217
|
+
| Value | Description |
|
|
218
|
+
|-------|-------------|
|
|
219
|
+
| `false` | Disable formatting (default) |
|
|
220
|
+
| `true` | Auto-detect formatter (biome > prettier > eslint) |
|
|
221
|
+
| `'prettier'` | Use Prettier |
|
|
222
|
+
| `'eslint'` | Use ESLint --fix |
|
|
223
|
+
| `'biome'` | Use Biome |
|
|
224
|
+
| `{ tool, args }` | Full configuration object |
|
|
225
|
+
|
|
226
|
+
**Auto-Detection Priority:**
|
|
227
|
+
|
|
228
|
+
When `format: true`, Vectify looks for config files in this order:
|
|
229
|
+
1. `biome.json` / `biome.jsonc` → Uses Biome
|
|
230
|
+
2. `.prettierrc*` / `prettier.config.*` → Uses Prettier
|
|
231
|
+
3. `eslint.config.*` / `.eslintrc*` → Uses ESLint
|
|
232
|
+
|
|
233
|
+
**Full Configuration:**
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
export default defineConfig({
|
|
237
|
+
format: {
|
|
238
|
+
tool: 'prettier', // 'auto' | 'prettier' | 'eslint' | 'biome'
|
|
239
|
+
args: '--single-quote', // Additional CLI arguments
|
|
240
|
+
},
|
|
241
|
+
})
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Examples:**
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
// Auto-detect formatter
|
|
248
|
+
format: true
|
|
249
|
+
|
|
250
|
+
// Use specific formatter
|
|
251
|
+
format: 'prettier'
|
|
252
|
+
format: 'eslint'
|
|
253
|
+
format: 'biome'
|
|
254
|
+
|
|
255
|
+
// With custom arguments
|
|
256
|
+
format: {
|
|
257
|
+
tool: 'prettier',
|
|
258
|
+
args: '--tab-width 4',
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Disable formatting
|
|
262
|
+
format: false
|
|
263
|
+
```
|
|
264
|
+
|
|
198
265
|
#### `watch` Object
|
|
199
266
|
|
|
200
267
|
| Parameter | Type | Default | Description | Example |
|
package/README.zh-CN.md
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
- [配置选项](#配置选项)
|
|
21
21
|
- [基础配置](#基础配置)
|
|
22
22
|
- [生成选项](#生成选项)
|
|
23
|
+
- [自动格式化](#自动格式化)
|
|
23
24
|
- [监听模式](#监听模式)
|
|
24
25
|
- [SVGO 配置](#svgo-配置)
|
|
25
26
|
- [生命周期钩子](#生命周期钩子)
|
|
@@ -185,6 +186,7 @@ npx vectify watch [选项]
|
|
|
185
186
|
| `prefix` | `string` | `''` | ❌ | 添加到所有组件名称前的前缀。用于命名空间 | `prefix: 'Icon'` → `IconArrowRight` |
|
|
186
187
|
| `suffix` | `string` | `''` | ❌ | 添加到所有组件名称后的后缀 | `suffix: 'Icon'` → `ArrowRightIcon` |
|
|
187
188
|
| `transform` | `(name: string) => string` | - | ❌ | 自定义函数,将 SVG 文件名转换为组件名。覆盖默认的 PascalCase 转换和 prefix/suffix | `transform: (n) => 'X' + n` |
|
|
189
|
+
| `format` | `boolean` \| `'prettier'` \| `'eslint'` \| `'biome'` \| `FormatConfig` | `false` | ❌ | 生成后自动格式化文件。详见 [自动格式化](#自动格式化) | `format: true` |
|
|
188
190
|
|
|
189
191
|
#### `generateOptions` 对象
|
|
190
192
|
|
|
@@ -195,6 +197,71 @@ npx vectify watch [选项]
|
|
|
195
197
|
| `preview` | `boolean` | `false` | 生成交互式 `preview.html` 用于本地浏览所有图标。适合设计审查 | `preview: true` |
|
|
196
198
|
| `cleanOutput` | `boolean` | `false` | 移除不再有对应 SVG 文件的孤立组件。帮助保持输出目录整洁 | `cleanOutput: true` |
|
|
197
199
|
|
|
200
|
+
#### 自动格式化
|
|
201
|
+
|
|
202
|
+
Vectify 可以使用项目中的格式化工具自动格式化生成的文件。确保生成的代码符合项目的代码风格。
|
|
203
|
+
|
|
204
|
+
**快速开始:**
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
export default defineConfig({
|
|
208
|
+
framework: 'react',
|
|
209
|
+
input: './icons',
|
|
210
|
+
output: './src/icons',
|
|
211
|
+
format: true, // 自动检测并使用项目格式化工具
|
|
212
|
+
})
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**格式化选项:**
|
|
216
|
+
|
|
217
|
+
| 值 | 说明 |
|
|
218
|
+
|----|------|
|
|
219
|
+
| `false` | 禁用格式化(默认) |
|
|
220
|
+
| `true` | 自动检测格式化工具(biome > prettier > eslint) |
|
|
221
|
+
| `'prettier'` | 使用 Prettier |
|
|
222
|
+
| `'eslint'` | 使用 ESLint --fix |
|
|
223
|
+
| `'biome'` | 使用 Biome |
|
|
224
|
+
| `{ tool, args }` | 完整配置对象 |
|
|
225
|
+
|
|
226
|
+
**自动检测优先级:**
|
|
227
|
+
|
|
228
|
+
当 `format: true` 时,Vectify 按以下顺序查找配置文件:
|
|
229
|
+
1. `biome.json` / `biome.jsonc` → 使用 Biome
|
|
230
|
+
2. `.prettierrc*` / `prettier.config.*` → 使用 Prettier
|
|
231
|
+
3. `eslint.config.*` / `.eslintrc*` → 使用 ESLint
|
|
232
|
+
|
|
233
|
+
**完整配置:**
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
export default defineConfig({
|
|
237
|
+
format: {
|
|
238
|
+
tool: 'prettier', // 'auto' | 'prettier' | 'eslint' | 'biome'
|
|
239
|
+
args: '--single-quote', // 额外的 CLI 参数
|
|
240
|
+
},
|
|
241
|
+
})
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**示例:**
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
// 自动检测格式化工具
|
|
248
|
+
format: true
|
|
249
|
+
|
|
250
|
+
// 使用指定的格式化工具
|
|
251
|
+
format: 'prettier'
|
|
252
|
+
format: 'eslint'
|
|
253
|
+
format: 'biome'
|
|
254
|
+
|
|
255
|
+
// 带自定义参数
|
|
256
|
+
format: {
|
|
257
|
+
tool: 'prettier',
|
|
258
|
+
args: '--tab-width 4',
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// 禁用格式化
|
|
262
|
+
format: false
|
|
263
|
+
```
|
|
264
|
+
|
|
198
265
|
#### `watch` 对象
|
|
199
266
|
|
|
200
267
|
| 参数 | 类型 | 默认值 | 说明 | 示例 |
|
|
@@ -135,6 +135,10 @@ function getVueTemplatePath(typescript, type) {
|
|
|
135
135
|
const suffix = typescript ? "ts" : "js";
|
|
136
136
|
return `vue/${type}.${suffix}.vue.hbs`;
|
|
137
137
|
}
|
|
138
|
+
function getVue2TemplatePath(typescript, type) {
|
|
139
|
+
const suffix = typescript ? "ts" : "js";
|
|
140
|
+
return `vue2/${type}.${suffix}.vue.hbs`;
|
|
141
|
+
}
|
|
138
142
|
function getSvelteTemplatePath(typescript, type) {
|
|
139
143
|
const suffix = typescript ? "ts" : "js";
|
|
140
144
|
return `svelte/${type}.${suffix}.svelte.hbs`;
|
|
@@ -324,6 +328,21 @@ function generateVueIcon(typescript) {
|
|
|
324
328
|
return renderTemplate(templatePath, { typescript });
|
|
325
329
|
}
|
|
326
330
|
|
|
331
|
+
// src/generators/vue2.ts
|
|
332
|
+
function generateVue2Component(componentName, iconNode, typescript) {
|
|
333
|
+
const formattedNodes = iconNode.map((node) => formatIconNode(node, 4)).join(",\n");
|
|
334
|
+
const templatePath = getVue2TemplatePath(typescript, "component");
|
|
335
|
+
return renderTemplate(templatePath, {
|
|
336
|
+
typescript,
|
|
337
|
+
componentName,
|
|
338
|
+
formattedNodes
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
function generateVue2Icon(typescript) {
|
|
342
|
+
const templatePath = getVue2TemplatePath(typescript, "icon");
|
|
343
|
+
return renderTemplate(templatePath, { typescript });
|
|
344
|
+
}
|
|
345
|
+
|
|
327
346
|
// src/generators/framework-strategy.ts
|
|
328
347
|
var ReactStrategy = class {
|
|
329
348
|
constructor() {
|
|
@@ -365,6 +384,26 @@ var VueStrategy = class {
|
|
|
365
384
|
};
|
|
366
385
|
}
|
|
367
386
|
};
|
|
387
|
+
var Vue2Strategy = class {
|
|
388
|
+
constructor() {
|
|
389
|
+
this.name = "vue2";
|
|
390
|
+
this.getComponentExtension = (_typescript) => {
|
|
391
|
+
return "vue";
|
|
392
|
+
};
|
|
393
|
+
this.getIndexExtension = (typescript) => {
|
|
394
|
+
return typescript ? "ts" : "js";
|
|
395
|
+
};
|
|
396
|
+
this.generateComponent = (componentName, iconNode, typescript) => {
|
|
397
|
+
return generateVue2Component(componentName, iconNode, typescript);
|
|
398
|
+
};
|
|
399
|
+
this.generateBaseComponent = (typescript) => {
|
|
400
|
+
return {
|
|
401
|
+
code: generateVue2Icon(typescript),
|
|
402
|
+
fileName: "Icon.vue"
|
|
403
|
+
};
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
};
|
|
368
407
|
var SvelteStrategy = class {
|
|
369
408
|
constructor() {
|
|
370
409
|
this.name = "svelte";
|
|
@@ -509,6 +548,7 @@ var FrameworkRegistry = class {
|
|
|
509
548
|
this.strategies = /* @__PURE__ */ new Map();
|
|
510
549
|
this.register(new ReactStrategy());
|
|
511
550
|
this.register(new VueStrategy());
|
|
551
|
+
this.register(new Vue2Strategy());
|
|
512
552
|
this.register(new SvelteStrategy());
|
|
513
553
|
this.register(new SolidStrategy());
|
|
514
554
|
this.register(new PreactStrategy());
|
|
@@ -639,7 +679,7 @@ async function findConfig() {
|
|
|
639
679
|
}
|
|
640
680
|
|
|
641
681
|
// src/generators/index.ts
|
|
642
|
-
import
|
|
682
|
+
import path4 from "path";
|
|
643
683
|
|
|
644
684
|
// src/parsers/optimizer.ts
|
|
645
685
|
import { optimize } from "svgo";
|
|
@@ -673,6 +713,100 @@ async function optimizeSvg(svgContent, config) {
|
|
|
673
713
|
}
|
|
674
714
|
}
|
|
675
715
|
|
|
716
|
+
// src/utils/formatter.ts
|
|
717
|
+
import { exec } from "child_process";
|
|
718
|
+
import path3 from "path";
|
|
719
|
+
import process3 from "process";
|
|
720
|
+
import { promisify } from "util";
|
|
721
|
+
var execAsync = promisify(exec);
|
|
722
|
+
var FORMATTER_PATTERNS = {
|
|
723
|
+
biome: ["biome.json", "biome.jsonc"],
|
|
724
|
+
prettier: [
|
|
725
|
+
".prettierrc",
|
|
726
|
+
".prettierrc.json",
|
|
727
|
+
".prettierrc.yml",
|
|
728
|
+
".prettierrc.yaml",
|
|
729
|
+
".prettierrc.js",
|
|
730
|
+
".prettierrc.cjs",
|
|
731
|
+
".prettierrc.mjs",
|
|
732
|
+
"prettier.config.js",
|
|
733
|
+
"prettier.config.cjs",
|
|
734
|
+
"prettier.config.mjs"
|
|
735
|
+
],
|
|
736
|
+
eslint: [
|
|
737
|
+
"eslint.config.js",
|
|
738
|
+
"eslint.config.mjs",
|
|
739
|
+
"eslint.config.cjs",
|
|
740
|
+
"eslint.config.ts",
|
|
741
|
+
".eslintrc",
|
|
742
|
+
".eslintrc.js",
|
|
743
|
+
".eslintrc.cjs",
|
|
744
|
+
".eslintrc.json",
|
|
745
|
+
".eslintrc.yml",
|
|
746
|
+
".eslintrc.yaml"
|
|
747
|
+
]
|
|
748
|
+
};
|
|
749
|
+
var FORMATTER_COMMANDS = {
|
|
750
|
+
biome: (outputDir, args) => `npx @biomejs/biome format --write ${args || ""} "${outputDir}"`.trim(),
|
|
751
|
+
prettier: (outputDir, args) => `npx prettier --write ${args || ""} "${outputDir}"`.trim(),
|
|
752
|
+
eslint: (outputDir, args) => `npx eslint --fix ${args || ""} "${outputDir}"`.trim()
|
|
753
|
+
};
|
|
754
|
+
function normalizeFormatOption(format) {
|
|
755
|
+
if (format === false) {
|
|
756
|
+
return null;
|
|
757
|
+
}
|
|
758
|
+
if (format === true) {
|
|
759
|
+
return { tool: "auto" };
|
|
760
|
+
}
|
|
761
|
+
if (typeof format === "string") {
|
|
762
|
+
return { tool: format };
|
|
763
|
+
}
|
|
764
|
+
return format;
|
|
765
|
+
}
|
|
766
|
+
async function detectFormatter() {
|
|
767
|
+
const cwd = process3.cwd();
|
|
768
|
+
const priority = ["biome", "prettier", "eslint"];
|
|
769
|
+
for (const tool of priority) {
|
|
770
|
+
const patterns = FORMATTER_PATTERNS[tool];
|
|
771
|
+
for (const pattern of patterns) {
|
|
772
|
+
const configPath = path3.join(cwd, pattern);
|
|
773
|
+
if (await fileExists(configPath)) {
|
|
774
|
+
return tool;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
async function formatOutput(outputDir, format) {
|
|
781
|
+
const config = normalizeFormatOption(format);
|
|
782
|
+
if (!config) {
|
|
783
|
+
return { success: true };
|
|
784
|
+
}
|
|
785
|
+
let tool = null;
|
|
786
|
+
if (config.tool === "auto") {
|
|
787
|
+
tool = await detectFormatter();
|
|
788
|
+
if (!tool) {
|
|
789
|
+
return {
|
|
790
|
+
success: true,
|
|
791
|
+
error: "No formatter detected. Install prettier, eslint, or biome to enable auto-formatting."
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
} else {
|
|
795
|
+
tool = config.tool || "prettier";
|
|
796
|
+
}
|
|
797
|
+
const command = FORMATTER_COMMANDS[tool](outputDir, config.args);
|
|
798
|
+
try {
|
|
799
|
+
await execAsync(command, { cwd: process3.cwd() });
|
|
800
|
+
return { success: true, tool };
|
|
801
|
+
} catch (error) {
|
|
802
|
+
return {
|
|
803
|
+
success: false,
|
|
804
|
+
tool,
|
|
805
|
+
error: `Format failed with ${tool}: ${error.message}`
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
676
810
|
// src/generators/index.ts
|
|
677
811
|
async function generateIcons(config, dryRun = false) {
|
|
678
812
|
const stats = {
|
|
@@ -714,6 +848,14 @@ async function generateIcons(config, dryRun = false) {
|
|
|
714
848
|
if (config.generateOptions?.preview && !dryRun) {
|
|
715
849
|
await generatePreviewHtml(svgFiles, config);
|
|
716
850
|
}
|
|
851
|
+
if (config.format && !dryRun) {
|
|
852
|
+
const formatResult = await formatOutput(config.output, config.format);
|
|
853
|
+
if (formatResult.success && formatResult.tool) {
|
|
854
|
+
console.log(`Formatted with ${formatResult.tool}`);
|
|
855
|
+
} else if (formatResult.error) {
|
|
856
|
+
console.warn(formatResult.error);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
717
859
|
if (config.hooks?.onComplete) {
|
|
718
860
|
await config.hooks.onComplete(stats);
|
|
719
861
|
}
|
|
@@ -724,7 +866,7 @@ async function generateIcons(config, dryRun = false) {
|
|
|
724
866
|
}
|
|
725
867
|
async function generateIconComponent(svgFile, config, dryRun = false) {
|
|
726
868
|
let svgContent = await readFile(svgFile);
|
|
727
|
-
const fileName =
|
|
869
|
+
const fileName = path4.basename(svgFile);
|
|
728
870
|
if (config.hooks?.beforeParse) {
|
|
729
871
|
svgContent = await config.hooks.beforeParse(svgContent, fileName);
|
|
730
872
|
}
|
|
@@ -748,7 +890,7 @@ async function generateIconComponent(svgFile, config, dryRun = false) {
|
|
|
748
890
|
code = await config.hooks.afterGenerate(code, componentName);
|
|
749
891
|
}
|
|
750
892
|
const fileExt = strategy.getComponentExtension(typescript);
|
|
751
|
-
const outputPath =
|
|
893
|
+
const outputPath = path4.join(config.output, `${componentName}.${fileExt}`);
|
|
752
894
|
if (dryRun) {
|
|
753
895
|
console.log(` ${componentName}.${fileExt}`);
|
|
754
896
|
} else {
|
|
@@ -759,7 +901,7 @@ async function generateBaseComponent(config, dryRun = false) {
|
|
|
759
901
|
const typescript = config.typescript ?? true;
|
|
760
902
|
const strategy = getFrameworkStrategy(config.framework);
|
|
761
903
|
const { code, fileName } = strategy.generateBaseComponent(typescript);
|
|
762
|
-
const outputPath =
|
|
904
|
+
const outputPath = path4.join(config.output, fileName);
|
|
763
905
|
if (dryRun) {
|
|
764
906
|
console.log(` ${fileName}`);
|
|
765
907
|
} else {
|
|
@@ -772,7 +914,7 @@ async function generateIndexFile(svgFiles, config, dryRun = false) {
|
|
|
772
914
|
const ext = strategy.getIndexExtension(typescript);
|
|
773
915
|
const usesDefaultExport = ["vue", "svelte", "react", "preact"].includes(config.framework);
|
|
774
916
|
const exports = svgFiles.map((svgFile) => {
|
|
775
|
-
const fileName =
|
|
917
|
+
const fileName = path4.basename(svgFile);
|
|
776
918
|
const componentName = getComponentName(
|
|
777
919
|
fileName,
|
|
778
920
|
config.prefix,
|
|
@@ -785,7 +927,7 @@ async function generateIndexFile(svgFiles, config, dryRun = false) {
|
|
|
785
927
|
return `export { ${componentName} } from './${componentName}'`;
|
|
786
928
|
}
|
|
787
929
|
}).join("\n");
|
|
788
|
-
const indexPath =
|
|
930
|
+
const indexPath = path4.join(config.output, `index.${ext}`);
|
|
789
931
|
if (dryRun) {
|
|
790
932
|
console.log(` index.${ext}`);
|
|
791
933
|
} else {
|
|
@@ -795,7 +937,7 @@ async function generateIndexFile(svgFiles, config, dryRun = false) {
|
|
|
795
937
|
}
|
|
796
938
|
async function generatePreviewHtml(svgFiles, config) {
|
|
797
939
|
const componentNames = svgFiles.map((svgFile) => {
|
|
798
|
-
const fileName =
|
|
940
|
+
const fileName = path4.basename(svgFile);
|
|
799
941
|
return getComponentName(
|
|
800
942
|
fileName,
|
|
801
943
|
config.prefix,
|
|
@@ -967,7 +1109,7 @@ async function generatePreviewHtml(svgFiles, config) {
|
|
|
967
1109
|
</script>
|
|
968
1110
|
</body>
|
|
969
1111
|
</html>`;
|
|
970
|
-
const previewPath =
|
|
1112
|
+
const previewPath = path4.join(config.output, "preview.html");
|
|
971
1113
|
await writeFile(previewPath, html);
|
|
972
1114
|
}
|
|
973
1115
|
async function cleanOutputDirectory(svgFiles, config) {
|
|
@@ -976,7 +1118,7 @@ async function cleanOutputDirectory(svgFiles, config) {
|
|
|
976
1118
|
const fileExt = strategy.getComponentExtension(config.typescript ?? true);
|
|
977
1119
|
const expectedComponents = new Set(
|
|
978
1120
|
svgFiles.map((svgFile) => {
|
|
979
|
-
const fileName =
|
|
1121
|
+
const fileName = path4.basename(svgFile, ".svg");
|
|
980
1122
|
const componentName = getComponentName(
|
|
981
1123
|
fileName,
|
|
982
1124
|
config.prefix,
|
|
@@ -1003,7 +1145,7 @@ async function cleanOutputDirectory(svgFiles, config) {
|
|
|
1003
1145
|
continue;
|
|
1004
1146
|
}
|
|
1005
1147
|
if (!expectedComponents.has(file)) {
|
|
1006
|
-
const filePath =
|
|
1148
|
+
const filePath = path4.join(config.output, file);
|
|
1007
1149
|
await unlink(filePath);
|
|
1008
1150
|
console.log(`Deleted orphaned component: ${file}`);
|
|
1009
1151
|
}
|
|
@@ -1072,15 +1214,15 @@ ${chalk.bold("Output:")} ${chalk.cyan(config.output)}`);
|
|
|
1072
1214
|
}
|
|
1073
1215
|
|
|
1074
1216
|
// src/commands/init.ts
|
|
1075
|
-
import
|
|
1076
|
-
import
|
|
1217
|
+
import path5 from "path";
|
|
1218
|
+
import process4 from "process";
|
|
1077
1219
|
import chalk2 from "chalk";
|
|
1078
1220
|
import inquirer from "inquirer";
|
|
1079
1221
|
import ora2 from "ora";
|
|
1080
1222
|
async function init(options = {}) {
|
|
1081
1223
|
try {
|
|
1082
1224
|
const projectRoot = await findProjectRoot();
|
|
1083
|
-
const currentDir =
|
|
1225
|
+
const currentDir = process4.cwd();
|
|
1084
1226
|
if (currentDir !== projectRoot) {
|
|
1085
1227
|
console.log(chalk2.yellow(`
|
|
1086
1228
|
Note: Project root detected at ${chalk2.cyan(projectRoot)}`));
|
|
@@ -1101,8 +1243,8 @@ Note: Project root detected at ${chalk2.cyan(projectRoot)}`));
|
|
|
1101
1243
|
}
|
|
1102
1244
|
}
|
|
1103
1245
|
]);
|
|
1104
|
-
const configPath =
|
|
1105
|
-
const configDir =
|
|
1246
|
+
const configPath = path5.resolve(projectRoot, pathAnswers.configPath);
|
|
1247
|
+
const configDir = path5.dirname(configPath);
|
|
1106
1248
|
if (!options.force && await fileExists(configPath)) {
|
|
1107
1249
|
const { overwrite } = await inquirer.prompt([
|
|
1108
1250
|
{
|
|
@@ -1129,6 +1271,16 @@ Note: Project root detected at ${chalk2.cyan(projectRoot)}`));
|
|
|
1129
1271
|
message: "Which framework are you using?",
|
|
1130
1272
|
choices: frameworkChoices
|
|
1131
1273
|
},
|
|
1274
|
+
{
|
|
1275
|
+
type: "list",
|
|
1276
|
+
name: "vueVersion",
|
|
1277
|
+
message: "Which Vue version?",
|
|
1278
|
+
choices: [
|
|
1279
|
+
{ name: "Vue 3", value: "vue" },
|
|
1280
|
+
{ name: "Vue 2", value: "vue2" }
|
|
1281
|
+
],
|
|
1282
|
+
when: (answers2) => answers2.framework === "vue"
|
|
1283
|
+
},
|
|
1132
1284
|
{
|
|
1133
1285
|
type: "input",
|
|
1134
1286
|
name: "input",
|
|
@@ -1166,15 +1318,16 @@ Note: Project root detected at ${chalk2.cyan(projectRoot)}`));
|
|
|
1166
1318
|
default: ""
|
|
1167
1319
|
}
|
|
1168
1320
|
]);
|
|
1169
|
-
const inputPath =
|
|
1170
|
-
const outputPath =
|
|
1321
|
+
const inputPath = path5.resolve(projectRoot, answers.input);
|
|
1322
|
+
const outputPath = path5.resolve(projectRoot, answers.output);
|
|
1171
1323
|
const spinner = ora2("Setting up directories...").start();
|
|
1172
1324
|
await ensureDir(inputPath);
|
|
1173
1325
|
spinner.text = `Created input directory: ${chalk2.cyan(answers.input)}`;
|
|
1174
1326
|
await ensureDir(outputPath);
|
|
1175
1327
|
spinner.succeed(`Created output directory: ${chalk2.cyan(answers.output)}`);
|
|
1176
|
-
const relativeConfigDir =
|
|
1177
|
-
const
|
|
1328
|
+
const relativeConfigDir = path5.relative(configDir, projectRoot) || ".";
|
|
1329
|
+
const finalFramework = answers.vueVersion || answers.framework;
|
|
1330
|
+
const configContent = generateConfigContent({ ...answers, framework: finalFramework }, relativeConfigDir);
|
|
1178
1331
|
spinner.start("Creating config file...");
|
|
1179
1332
|
await writeFile(configPath, configContent);
|
|
1180
1333
|
spinner.succeed(`Config file created at ${chalk2.green(configPath)}`);
|
|
@@ -1216,7 +1369,7 @@ export default defineConfig({
|
|
|
1216
1369
|
}
|
|
1217
1370
|
|
|
1218
1371
|
// src/commands/watch.ts
|
|
1219
|
-
import
|
|
1372
|
+
import path6 from "path";
|
|
1220
1373
|
import chalk3 from "chalk";
|
|
1221
1374
|
import chokidar from "chokidar";
|
|
1222
1375
|
import ora3 from "ora";
|
|
@@ -1238,7 +1391,7 @@ async function watch(options = {}) {
|
|
|
1238
1391
|
spinner.start("Generating icon components...");
|
|
1239
1392
|
const initialStats = await generateIcons(config);
|
|
1240
1393
|
spinner.succeed(`Generated ${chalk3.green(initialStats.success)} icon components`);
|
|
1241
|
-
const watchPath =
|
|
1394
|
+
const watchPath = path6.join(config.input, "**/*.svg");
|
|
1242
1395
|
const debounce = config.watch?.debounce ?? 300;
|
|
1243
1396
|
const ignore = config.watch?.ignore ?? ["**/node_modules/**", "**/.git/**"];
|
|
1244
1397
|
console.log(chalk3.bold("\nWatching for changes..."));
|
|
@@ -1256,7 +1409,7 @@ async function watch(options = {}) {
|
|
|
1256
1409
|
}).on("change", (filePath) => {
|
|
1257
1410
|
handleChange("changed", filePath, config, debounce, debounceTimer);
|
|
1258
1411
|
}).on("unlink", (filePath) => {
|
|
1259
|
-
console.log(chalk3.yellow(`SVG file removed: ${
|
|
1412
|
+
console.log(chalk3.yellow(`SVG file removed: ${path6.basename(filePath)}`));
|
|
1260
1413
|
handleChange("removed", filePath, config, debounce, debounceTimer);
|
|
1261
1414
|
}).on("error", (error) => {
|
|
1262
1415
|
console.error(chalk3.red(`Watcher error: ${error.message}`));
|
|
@@ -1275,7 +1428,7 @@ ${chalk3.yellow("Stopping watch mode...")}`);
|
|
|
1275
1428
|
}
|
|
1276
1429
|
}
|
|
1277
1430
|
function handleChange(event, filePath, config, debounce, timer) {
|
|
1278
|
-
const fileName =
|
|
1431
|
+
const fileName = path6.basename(filePath);
|
|
1279
1432
|
if (timer) {
|
|
1280
1433
|
clearTimeout(timer);
|
|
1281
1434
|
}
|