icon-to-font 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/bin/cli.js +11 -0
- package/bin/cli.ts +183 -0
- package/examples/uniapp-vue3/App.vue +17 -0
- package/examples/uniapp-vue3/index.html +20 -0
- package/examples/uniapp-vue3/main.js +22 -0
- package/examples/uniapp-vue3/manifest.json +72 -0
- package/examples/uniapp-vue3/pages/index/index.vue +33 -0
- package/examples/uniapp-vue3/pages.json +17 -0
- package/examples/uniapp-vue3/static/itf/test1.svg +1 -0
- package/examples/uniapp-vue3/static/itf/test2.svg +1 -0
- package/examples/uniapp-vue3/static/itf//346/265/213/350/257/225.svg +1 -0
- package/examples/uniapp-vue3/static/logo.png +0 -0
- package/examples/uniapp-vue3/uni.promisify.adaptor.js +13 -0
- package/examples/uniapp-vue3/uni.scss +76 -0
- package/examples/vite-react/README.md +73 -0
- package/examples/vite-react/eslint.config.js +23 -0
- package/examples/vite-react/index.html +13 -0
- package/examples/vite-react/package.json +30 -0
- package/examples/vite-react/pnpm-lock.yaml +2049 -0
- package/examples/vite-react/public/vite.svg +1 -0
- package/examples/vite-react/src/App.css +42 -0
- package/examples/vite-react/src/App.tsx +37 -0
- package/examples/vite-react/src/assets/itf/test1.svg +1 -0
- package/examples/vite-react/src/assets/itf/test2.svg +1 -0
- package/examples/vite-react/src/assets/itf//346/265/213/350/257/225.svg +1 -0
- package/examples/vite-react/src/assets/react.svg +1 -0
- package/examples/vite-react/src/index.css +68 -0
- package/examples/vite-react/src/main.tsx +10 -0
- package/examples/vite-react/tsconfig.app.json +28 -0
- package/examples/vite-react/tsconfig.json +7 -0
- package/examples/vite-react/tsconfig.node.json +26 -0
- package/examples/vite-react/vite.config.ts +7 -0
- package/examples/vite-vue3/.vscode/extensions.json +3 -0
- package/examples/vite-vue3/README.md +5 -0
- package/examples/vite-vue3/index.html +13 -0
- package/examples/vite-vue3/package.json +21 -0
- package/examples/vite-vue3/pnpm-lock.yaml +939 -0
- package/examples/vite-vue3/public/vite.svg +1 -0
- package/examples/vite-vue3/src/App.vue +30 -0
- package/examples/vite-vue3/src/assets/itf/test1.svg +1 -0
- package/examples/vite-vue3/src/assets/itf/test2.svg +1 -0
- package/examples/vite-vue3/src/assets/itf//346/265/213/350/257/225.svg +1 -0
- package/examples/vite-vue3/src/assets/vue.svg +1 -0
- package/examples/vite-vue3/src/components/HelloWorld.vue +41 -0
- package/examples/vite-vue3/src/main.ts +5 -0
- package/examples/vite-vue3/src/style.css +79 -0
- package/examples/vite-vue3/tsconfig.app.json +16 -0
- package/examples/vite-vue3/tsconfig.json +7 -0
- package/examples/vite-vue3/tsconfig.node.json +26 -0
- package/examples/vite-vue3/vite.config.ts +7 -0
- package/package.json +48 -0
- package/tsconfig.json +24 -0
- package/utils/command-line.ts +155 -0
- package/utils/component-generators/base-component-generator.abstract.ts +25 -0
- package/utils/component-generators/component-generator-factory.ts +32 -0
- package/utils/component-generators/component-generator.interface.ts +12 -0
- package/utils/component-generators/index.ts +11 -0
- package/utils/component-generators/react-component-generator.ts +69 -0
- package/utils/component-generators/uni-app-component-generator.ts +64 -0
- package/utils/component-generators/vue-component-generator.ts +65 -0
- package/utils/component-generators.ts +9 -0
- package/utils/css-generator.ts +47 -0
- package/utils/directory-structure.ts +139 -0
- package/utils/file-system.ts +83 -0
- package/utils/font-generator.ts +55 -0
- package/utils/project-detector.ts +145 -0
- package/utils/usage-generator.ts +77 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React 组件生成器
|
|
3
|
+
*/
|
|
4
|
+
import { BaseComponentGenerator } from './base-component-generator.abstract';
|
|
5
|
+
|
|
6
|
+
export class ReactComponentGenerator extends BaseComponentGenerator {
|
|
7
|
+
/**
|
|
8
|
+
* 生成 React 组件
|
|
9
|
+
* @param {string} fontName - 字体名称
|
|
10
|
+
* @param {string[]} iconNames - 图标名称数组
|
|
11
|
+
* @returns {string} React 组件内容
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const generator = new ReactComponentGenerator();
|
|
15
|
+
* const reactComponent = generator.generate('MyFont', ['icon1', 'icon2']);
|
|
16
|
+
* console.log(reactComponent); // 输出 React 组件内容
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
generate(fontName: string, iconNames: string[]): string {
|
|
20
|
+
const iconNameUnion = this.generateIconNameUnion(iconNames);
|
|
21
|
+
|
|
22
|
+
return `
|
|
23
|
+
import React from 'react';
|
|
24
|
+
import './icon-font.css';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Icon component props
|
|
28
|
+
*/
|
|
29
|
+
export interface ItfIconProps {
|
|
30
|
+
/** Icon name */
|
|
31
|
+
name: ${iconNameUnion};
|
|
32
|
+
/** Size in px or any valid CSS unit */
|
|
33
|
+
size?: number | string;
|
|
34
|
+
/** Color of the icon */
|
|
35
|
+
color?: string;
|
|
36
|
+
/** Additional className */
|
|
37
|
+
className?: string;
|
|
38
|
+
/** Click event handler */
|
|
39
|
+
onClick?: (event: React.MouseEvent<HTMLSpanElement>) => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Icon component
|
|
44
|
+
*/
|
|
45
|
+
const ItfIcon: React.FC<ItfIconProps> = ({
|
|
46
|
+
name,
|
|
47
|
+
size = 14,
|
|
48
|
+
color,
|
|
49
|
+
className = '',
|
|
50
|
+
onClick,
|
|
51
|
+
...rest
|
|
52
|
+
}) => {
|
|
53
|
+
return (
|
|
54
|
+
<span
|
|
55
|
+
className={\`itf-icon itf-icon-\${name} \${className}\`}
|
|
56
|
+
style={{
|
|
57
|
+
fontSize: typeof size === 'number' ? \`\${size}px\` : size,
|
|
58
|
+
color,
|
|
59
|
+
}}
|
|
60
|
+
onClick={onClick}
|
|
61
|
+
{...rest}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default ItfIcon;
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uni-app 组件生成器
|
|
3
|
+
*/
|
|
4
|
+
import { BaseComponentGenerator } from "./base-component-generator.abstract";
|
|
5
|
+
|
|
6
|
+
export class UniAppComponentGenerator extends BaseComponentGenerator {
|
|
7
|
+
/**
|
|
8
|
+
* 生成 uni-app 组件
|
|
9
|
+
* @param {string} fontName - 字体名称
|
|
10
|
+
* @param {string[]} iconNames - 图标名称数组
|
|
11
|
+
* @returns {string} uni-app 组件内容
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const generator = new UniAppComponentGenerator();
|
|
15
|
+
* const uniComponent = generator.generate('MyFont', ['icon1', 'icon2']);
|
|
16
|
+
* console.log(uniComponent); // 输出 uni-app 组件内容
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
generate(fontName: string, iconNames: string[]): string {
|
|
20
|
+
const iconNameUnion = this.generateIconNameUnion(iconNames);
|
|
21
|
+
|
|
22
|
+
return `
|
|
23
|
+
<template>
|
|
24
|
+
<text
|
|
25
|
+
:class="['itf-icon', \`itf-icon-\${props.name}\`]"
|
|
26
|
+
:style="{
|
|
27
|
+
fontSize: typeof props.size === 'number' ? \`\${props.size}px\` : props.size,
|
|
28
|
+
color: props.color
|
|
29
|
+
}"
|
|
30
|
+
@click="$emit('click', $event)"
|
|
31
|
+
/>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
export interface ItfIconProps {
|
|
36
|
+
/** Icon name */
|
|
37
|
+
name: ${iconNameUnion};
|
|
38
|
+
/** Size in px or any valid CSS unit */
|
|
39
|
+
size?: number | string;
|
|
40
|
+
/** Color of the icon */
|
|
41
|
+
color?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const props = withDefaults(defineProps<ItfIconProps>(), {
|
|
45
|
+
size: 30,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
defineEmits<{
|
|
49
|
+
click: [event: MouseEvent];
|
|
50
|
+
}>();
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<style scoped lang="scss">
|
|
54
|
+
@import '../../static/.itf/icon-font.css';
|
|
55
|
+
|
|
56
|
+
.itf-icon {
|
|
57
|
+
vertical-align: middle;
|
|
58
|
+
cursor: inherit;
|
|
59
|
+
speak: none;
|
|
60
|
+
}
|
|
61
|
+
</style>
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue 组件生成器
|
|
3
|
+
*/
|
|
4
|
+
import { BaseComponentGenerator } from './base-component-generator.abstract';
|
|
5
|
+
|
|
6
|
+
export class VueComponentGenerator extends BaseComponentGenerator {
|
|
7
|
+
/**
|
|
8
|
+
* 生成 Vue 组件
|
|
9
|
+
* @param {string} fontName - 字体名称
|
|
10
|
+
* @param {string[]} iconNames - 图标名称数组
|
|
11
|
+
* @returns {string} Vue 组件内容
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const generator = new VueComponentGenerator();
|
|
15
|
+
* const vueComponent = generator.generate('MyFont', ['icon1', 'icon2']);
|
|
16
|
+
* console.log(vueComponent); // 输出 Vue 组件内容
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
generate(fontName: string, iconNames: string[]): string {
|
|
20
|
+
const iconNameUnion = this.generateIconNameUnion(iconNames);
|
|
21
|
+
|
|
22
|
+
return `
|
|
23
|
+
<template>
|
|
24
|
+
<i
|
|
25
|
+
:class="['itf-icon', \`itf-icon-\${props.name}\`]"
|
|
26
|
+
:style="{
|
|
27
|
+
fontSize: typeof props.size === 'number' ? \`\${props.size}px\` : props.size,
|
|
28
|
+
color: props.color
|
|
29
|
+
}"
|
|
30
|
+
v-bind="$attrs"
|
|
31
|
+
@click="$emit('click', $event)"
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup lang="ts">
|
|
36
|
+
import './icon-font.css';
|
|
37
|
+
|
|
38
|
+
export interface ItfIconProps {
|
|
39
|
+
/** Icon name */
|
|
40
|
+
name: ${iconNameUnion};
|
|
41
|
+
/** Size in px or any valid CSS unit */
|
|
42
|
+
size?: number | string;
|
|
43
|
+
/** Color of the icon */
|
|
44
|
+
color?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const props = withDefaults(defineProps<ItfIconProps>(), {
|
|
48
|
+
size: 14,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
defineEmits<{
|
|
52
|
+
click: [event: MouseEvent];
|
|
53
|
+
}>();
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.itf-icon {
|
|
58
|
+
vertical-align: middle;
|
|
59
|
+
cursor: inherit;
|
|
60
|
+
speak: none;
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS 生成器模块
|
|
3
|
+
* @description 生成字体图标所需的 CSS 内容
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 生成 CSS 文件内容
|
|
8
|
+
* @param {string} fontName - 字体名称
|
|
9
|
+
* @param {string[]} iconNames - 图标名称数组
|
|
10
|
+
* @returns {string} CSS 内容
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const cssContent = generateCssContent('MyFont', ['icon1', 'icon2']);
|
|
14
|
+
* console.log(cssContent); // 输出 CSS 内容
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function generateCssContent(fontName: string, iconNames: string[]): string {
|
|
18
|
+
return `
|
|
19
|
+
@font-face {
|
|
20
|
+
font-family: '${fontName}';
|
|
21
|
+
src: url('./${fontName}.woff2') format('woff2');
|
|
22
|
+
font-weight: normal;
|
|
23
|
+
font-style: normal;
|
|
24
|
+
font-display: block;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.itf-icon {
|
|
28
|
+
font-family: '${fontName}' !important;
|
|
29
|
+
font-style: normal;
|
|
30
|
+
font-weight: normal;
|
|
31
|
+
font-variant: normal;
|
|
32
|
+
text-transform: none;
|
|
33
|
+
line-height: 1;
|
|
34
|
+
-webkit-font-smoothing: antialiased;
|
|
35
|
+
-moz-osx-font-smoothing: grayscale;
|
|
36
|
+
display: inline-block;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
${iconNames
|
|
40
|
+
.map((name, index) => {
|
|
41
|
+
const code = 0xf101 + index;
|
|
42
|
+
const codeStr = code.toString(16).padStart(4, '0');
|
|
43
|
+
return `.itf-icon-${name}::before { content: "\\${codeStr}"; }`;
|
|
44
|
+
})
|
|
45
|
+
.join("\n")}
|
|
46
|
+
`.trim();
|
|
47
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 目录结构处理模块
|
|
3
|
+
* @description 处理不同项目类型的目录结构
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 目录结构接口
|
|
10
|
+
*/
|
|
11
|
+
export interface DirectoryStructure {
|
|
12
|
+
/** 组件目录 */
|
|
13
|
+
componentDir: string;
|
|
14
|
+
/** 资源目录(字体文件和 CSS 文件) */
|
|
15
|
+
assetsDir: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 项目类型枚举
|
|
20
|
+
*/
|
|
21
|
+
export enum ProjectType {
|
|
22
|
+
/** Vue 项目 */
|
|
23
|
+
VUE = 'vue',
|
|
24
|
+
/** React 项目 */
|
|
25
|
+
REACT = 'react',
|
|
26
|
+
/** uni-app 项目 */
|
|
27
|
+
UNIAPP = 'uniapp',
|
|
28
|
+
/** 其他项目类型 */
|
|
29
|
+
OTHER = 'other'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 获取项目类型对应的目录结构
|
|
34
|
+
* @param {ProjectType | string} projectType - 项目类型
|
|
35
|
+
* @param {string} baseDistDir - 基础输出目录
|
|
36
|
+
* @returns {DirectoryStructure} 目录结构对象
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const structure = getDirectoryStructure('vue', './output');
|
|
40
|
+
* console.log(structure.componentDir); // 输出:./src/components
|
|
41
|
+
* console.log(structure.assetsDir); // 输出:./src/assets/.itf
|
|
42
|
+
*
|
|
43
|
+
* const uniAppStructure = getDirectoryStructure('uniapp', './examples/uniapp-vue3');
|
|
44
|
+
* console.log(uniAppStructure.componentDir); // 输出:./examples/uniapp-vue3/components
|
|
45
|
+
* console.log(uniAppStructure.assetsDir); // 输出:./examples/uniapp-vue3/static/.itf
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function getDirectoryStructure(
|
|
49
|
+
projectType: ProjectType | string,
|
|
50
|
+
baseDistDir: string
|
|
51
|
+
): DirectoryStructure {
|
|
52
|
+
const type = projectType as ProjectType;
|
|
53
|
+
|
|
54
|
+
switch (type) {
|
|
55
|
+
case ProjectType.UNIAPP:
|
|
56
|
+
// 对于 uni-app 项目,assetsDir 应该是在项目根目录下的 static/.itf
|
|
57
|
+
// 我们需要从 baseDistDir 中提取项目根目录
|
|
58
|
+
const uniAppRootDir = baseDistDir.includes('components') ? baseDistDir.replace('components', '') : baseDistDir;
|
|
59
|
+
return {
|
|
60
|
+
componentDir: resolve(process.cwd(), baseDistDir),
|
|
61
|
+
assetsDir: resolve(process.cwd(), uniAppRootDir, 'static/.itf')
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
case ProjectType.VUE:
|
|
65
|
+
case ProjectType.REACT:
|
|
66
|
+
return {
|
|
67
|
+
componentDir: resolve(process.cwd(), baseDistDir),
|
|
68
|
+
assetsDir: resolve(process.cwd(), 'src/assets/.itf')
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
default:
|
|
72
|
+
return {
|
|
73
|
+
componentDir: resolve(process.cwd(), baseDistDir),
|
|
74
|
+
assetsDir: resolve(process.cwd(), baseDistDir)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 获取组件文件路径
|
|
81
|
+
* @param {DirectoryStructure} structure - 目录结构
|
|
82
|
+
* @param {ProjectType | string} projectType - 项目类型
|
|
83
|
+
* @returns {string} 组件文件路径
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const structure = getDirectoryStructure('vue', './output');
|
|
87
|
+
* const componentPath = getComponentFilePath(structure, 'vue');
|
|
88
|
+
* console.log(componentPath); // 输出:./src/components/ItfIcon/ItfIcon.vue
|
|
89
|
+
*
|
|
90
|
+
* const reactStructure = getDirectoryStructure('react', './output');
|
|
91
|
+
* const reactComponentPath = getComponentFilePath(reactStructure, 'react');
|
|
92
|
+
* console.log(reactComponentPath); // 输出:./src/components/ItfIcon/ItfIcon.tsx
|
|
93
|
+
*
|
|
94
|
+
* const uniAppStructure = getDirectoryStructure('uniapp', './output');
|
|
95
|
+
* const uniAppComponentPath = getComponentFilePath(uniAppStructure, 'uniapp');
|
|
96
|
+
* console.log(uniAppComponentPath); // 输出:./components/ItfIcon/ItfIcon.vue
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function getComponentFilePath(
|
|
100
|
+
structure: DirectoryStructure,
|
|
101
|
+
projectType: ProjectType | string
|
|
102
|
+
): string {
|
|
103
|
+
const type = projectType as ProjectType;
|
|
104
|
+
const extension = type === ProjectType.REACT ? 'tsx' : 'vue';
|
|
105
|
+
|
|
106
|
+
// 所有项目类型都输出到 ItfIcon 子目录中
|
|
107
|
+
return resolve(structure.componentDir, 'ItfIcon', `ItfIcon.${extension}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 获取 CSS 文件路径
|
|
112
|
+
* @param {DirectoryStructure} structure - 目录结构
|
|
113
|
+
* @returns {string} CSS 文件路径
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const structure = getDirectoryStructure('vue', './output');
|
|
117
|
+
* const cssPath = getCssFilePath(structure);
|
|
118
|
+
* console.log(cssPath); // 输出:./src/assets/.itf/icon-font.css
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function getCssFilePath(structure: DirectoryStructure): string {
|
|
122
|
+
return resolve(structure.assetsDir, 'icon-font.css');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 获取字体文件路径
|
|
127
|
+
* @param {DirectoryStructure} structure - 目录结构
|
|
128
|
+
* @param {string} fontName - 字体名称
|
|
129
|
+
* @returns {string} 字体文件路径
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const structure = getDirectoryStructure('vue', './output');
|
|
133
|
+
* const fontPath = getFontFilePath(structure, 'MyIconFont');
|
|
134
|
+
* console.log(fontPath); // 输出:./src/assets/.itf/MyIconFont
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export function getFontFilePath(structure: DirectoryStructure, fontName: string): string {
|
|
138
|
+
return resolve(structure.assetsDir, fontName);
|
|
139
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文件系统操作模块
|
|
3
|
+
* @description 封装文件系统相关操作
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 检查目录是否存在
|
|
11
|
+
* @param {string} directory - 目录路径
|
|
12
|
+
* @returns {boolean} 是否存在
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const exists = checkDirectoryExists('./src');
|
|
16
|
+
* console.log(exists); // 输出:true 或 false
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function checkDirectoryExists(directory: string): boolean {
|
|
20
|
+
return existsSync(directory);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 创建目录(如果不存在)
|
|
25
|
+
* @param {string} directory - 目录路径
|
|
26
|
+
* @returns {void}
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* createDirectory('./output');
|
|
30
|
+
* // 创建 output 目录(如果不存在)
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function createDirectory(directory: string): void {
|
|
34
|
+
mkdirSync(directory, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 写入文件
|
|
39
|
+
* @param {string} filePath - 文件路径
|
|
40
|
+
* @param {string} content - 文件内容
|
|
41
|
+
* @returns {void}
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* writeFile('./output/file.txt', 'Hello World');
|
|
45
|
+
* // 写入文件内容
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function writeFile(filePath: string, content: string): void {
|
|
49
|
+
writeFileSync(filePath, content, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 读取目录中的文件
|
|
54
|
+
* @param {string} directory - 目录路径
|
|
55
|
+
* @param {string} extension - 文件扩展名(可选)
|
|
56
|
+
* @returns {string[]} 文件名称数组
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const files = readDirectory('./icons', '.svg');
|
|
60
|
+
* console.log(files); // 输出:['icon1.svg', 'icon2.svg']
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function readDirectory(directory: string, extension?: string): string[] {
|
|
64
|
+
const files = readdirSync(directory);
|
|
65
|
+
if (extension) {
|
|
66
|
+
return files.filter(file => file.endsWith(extension));
|
|
67
|
+
}
|
|
68
|
+
return files;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 解析绝对路径
|
|
73
|
+
* @param {string} path - 相对或绝对路径
|
|
74
|
+
* @returns {string} 绝对路径
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const absolutePath = resolvePath('./src');
|
|
78
|
+
* console.log(absolutePath); // 输出:/full/path/to/src
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function resolvePath(path: string): string {
|
|
82
|
+
return resolve(process.cwd(), path);
|
|
83
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 字体生成器模块
|
|
3
|
+
* @description 用于生成字体文件
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import webfontsGenerator from '@vusion/webfonts-generator';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 生成字体文件的选项接口
|
|
10
|
+
*/
|
|
11
|
+
export interface GenerateFontOptions {
|
|
12
|
+
/** SVG 文件路径数组 */
|
|
13
|
+
svgFiles: string[];
|
|
14
|
+
/** 输出目录 */
|
|
15
|
+
outputDir: string;
|
|
16
|
+
/** 字体名称 */
|
|
17
|
+
fontName: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 生成字体文件
|
|
22
|
+
* @param {GenerateFontOptions} options - 生成选项
|
|
23
|
+
* @returns {Promise<void>} - 生成完成的 Promise
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* await generateFont({
|
|
27
|
+
* svgFiles: ['/path/to/icon1.svg', '/path/to/icon2.svg'],
|
|
28
|
+
* outputDir: '/path/to/output',
|
|
29
|
+
* fontName: 'MyIconFont'
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export async function generateFont(options: GenerateFontOptions): Promise<void> {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
webfontsGenerator({
|
|
36
|
+
files: options.svgFiles,
|
|
37
|
+
dest: options.outputDir,
|
|
38
|
+
fontName: options.fontName,
|
|
39
|
+
types: ['woff2'],
|
|
40
|
+
css: false,
|
|
41
|
+
html: false,
|
|
42
|
+
order: ['woff2'],
|
|
43
|
+
templateOptions: {
|
|
44
|
+
baseClass: 'my-icon',
|
|
45
|
+
classPrefix: 'my-icon-'
|
|
46
|
+
}
|
|
47
|
+
}, (error) => {
|
|
48
|
+
if (error) {
|
|
49
|
+
reject(error);
|
|
50
|
+
} else {
|
|
51
|
+
resolve();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目类型检测器模块
|
|
3
|
+
* @description 用于检测一个文件夹下的项目类型(uniapp、vue、react)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 项目类型枚举
|
|
11
|
+
*/
|
|
12
|
+
export enum ProjectType {
|
|
13
|
+
/** uniapp 项目 */
|
|
14
|
+
UNIAPP = 'uniapp',
|
|
15
|
+
/** Vue 项目 */
|
|
16
|
+
VUE = 'vue',
|
|
17
|
+
/** React 项目 */
|
|
18
|
+
REACT = 'react',
|
|
19
|
+
/** 未知项目类型 */
|
|
20
|
+
UNKNOWN = 'unknown'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 检测项目类型
|
|
25
|
+
* @param {string} directory - 要检测的目录路径
|
|
26
|
+
* @returns {ProjectType} 项目类型
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const projectType = detectProjectType('./my-project');
|
|
30
|
+
* console.log(projectType); // 输出:ProjectType.VUE
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function detectProjectType(directory: string): ProjectType {
|
|
34
|
+
// 检查是否为 uniapp 项目
|
|
35
|
+
if (isUniappProject(directory)) {
|
|
36
|
+
return ProjectType.UNIAPP;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 检查是否为 React 项目
|
|
40
|
+
if (isReactProject(directory)) {
|
|
41
|
+
return ProjectType.REACT;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 检查是否为 Vue 项目
|
|
45
|
+
if (isVueProject(directory)) {
|
|
46
|
+
return ProjectType.VUE;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 未知项目类型
|
|
50
|
+
return ProjectType.UNKNOWN;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 检查是否为 uniapp 项目
|
|
55
|
+
* @param {string} directory - 目录路径
|
|
56
|
+
* @returns {boolean} 是否为 uniapp 项目
|
|
57
|
+
*/
|
|
58
|
+
function isUniappProject(directory: string): boolean {
|
|
59
|
+
// uniapp 项目的特征文件
|
|
60
|
+
const uniappFiles = [
|
|
61
|
+
join(directory, 'pages.json'),
|
|
62
|
+
join(directory, 'manifest.json'),
|
|
63
|
+
join(directory, 'uni.scss')
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
// 检查是否存在 uniapp 特征文件
|
|
67
|
+
return uniappFiles.some(file => existsSync(file));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 检查是否为 Vue 项目
|
|
72
|
+
* @param {string} directory - 目录路径
|
|
73
|
+
* @returns {boolean} 是否为 Vue 项目
|
|
74
|
+
*/
|
|
75
|
+
function isVueProject(directory: string): boolean {
|
|
76
|
+
// Vue 项目的特征文件
|
|
77
|
+
const vueConfigFiles = [
|
|
78
|
+
join(directory, 'vue.config.js'),
|
|
79
|
+
join(directory, 'vite.config.js'),
|
|
80
|
+
join(directory, 'vite.config.ts'),
|
|
81
|
+
join(directory, 'nuxt.config.js'),
|
|
82
|
+
join(directory, 'nuxt.config.ts')
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
// 检查是否存在 Vue 配置文件
|
|
86
|
+
if (vueConfigFiles.some(file => existsSync(file))) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 检查 package.json 中是否有 Vue 相关依赖
|
|
91
|
+
return hasDependency(directory, ['vue', '@vue/cli-service', 'nuxt', 'vite']);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 检查是否为 React 项目
|
|
96
|
+
* @param {string} directory - 目录路径
|
|
97
|
+
* @returns {boolean} 是否为 React 项目
|
|
98
|
+
*/
|
|
99
|
+
function isReactProject(directory: string): boolean {
|
|
100
|
+
// React 项目的特征文件
|
|
101
|
+
const reactConfigFiles = [
|
|
102
|
+
join(directory, 'webpack.config.js'),
|
|
103
|
+
join(directory, 'craco.config.js'),
|
|
104
|
+
join(directory, 'next.config.js')
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
// 检查是否存在 React 配置文件
|
|
108
|
+
if (reactConfigFiles.some(file => existsSync(file))) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 检查 package.json 中是否有 React 相关依赖
|
|
113
|
+
return hasDependency(directory, ['react', 'react-dom', 'next', 'gatsby']);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 检查 package.json 中是否有指定的依赖
|
|
118
|
+
* @param {string} directory - 目录路径
|
|
119
|
+
* @param {string[]} dependencies - 要检查的依赖名称数组
|
|
120
|
+
* @returns {boolean} 是否有指定的依赖
|
|
121
|
+
*/
|
|
122
|
+
function hasDependency(directory: string, dependencies: string[]): boolean {
|
|
123
|
+
const packageJsonPath = join(directory, 'package.json');
|
|
124
|
+
|
|
125
|
+
if (!existsSync(packageJsonPath)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
131
|
+
|
|
132
|
+
// 检查 dependencies、devDependencies 和 peerDependencies
|
|
133
|
+
const allDependencies = {
|
|
134
|
+
...packageJson.dependencies,
|
|
135
|
+
...packageJson.devDependencies,
|
|
136
|
+
...packageJson.peerDependencies
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// 检查是否有指定的依赖
|
|
140
|
+
return dependencies.some(dep => allDependencies[dep]);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// 解析 package.json 失败
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|