-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathgenerateComponent.ts
More file actions
157 lines (125 loc) · 5.25 KB
/
generateComponent.ts
File metadata and controls
157 lines (125 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import glob from 'glob';
import colors from 'colors';
import { camelCase, upperFirst } from 'lodash';
import { XmlData } from 'iconfont-parser';
import { Config } from './getConfig';
import { getTemplate } from './getTemplate';
import {
replaceCases,
replaceComponentName,
replaceDefaultStyle,
replaceExports,
replaceImports,
replaceNames,
replaceNamesArray,
replaceSingleIconContent,
replaceSize,
replaceSizeUnit,
} from './replace';
import { whitespace } from './whitespace';
import { copyTemplate } from './copyTemplate';
const ATTRIBUTE_FILL_MAP = ['path'];
export const generateComponent = (data: XmlData, config: Config) => {
const names: string[] = [];
const imports: string[] = [];
const saveDir = path.resolve(config.save_dir);
const jsxExtension = config.use_typescript ? '.tsx' : '.js';
const jsExtension = config.use_typescript ? '.ts' : '.js';
let cases: string = '';
mkdirp.sync(saveDir);
glob.sync(path.join(saveDir, '*')).forEach((file) => fs.unlinkSync(file));
copyTemplate(`helper${jsExtension}`, path.join(saveDir, `helper${jsExtension}`));
if (!config.use_typescript) {
copyTemplate('helper.d.ts', path.join(saveDir, 'helper.d.ts'));
}
data.svg.symbol.forEach((item) => {
let singleFile: string;
const iconId = item.$.id;
const iconIdAfterTrim = config.trim_icon_prefix
? iconId.replace(
new RegExp(`^${config.trim_icon_prefix}(.+?)$`),
(_, value) => value.replace(/^[-_.=+#@!~*]+(.+?)$/, '$1')
)
: iconId;
const componentName = upperFirst(camelCase(iconId));
names.push(iconIdAfterTrim);
cases += `${whitespace(4)}case '${iconIdAfterTrim}':\n`;
imports.push(componentName);
cases += `${whitespace(6)}return <${componentName} {...rest} />;\n`;
singleFile = getTemplate('SingleIcon' + jsxExtension);
singleFile = replaceSize(singleFile, config.default_icon_size);
singleFile = replaceComponentName(singleFile, componentName);
singleFile = replaceSingleIconContent(singleFile, generateCase(item, 4));
singleFile = replaceSizeUnit(singleFile, config.unit);
singleFile = replaceDefaultStyle(singleFile, config.default_style);
fs.writeFileSync(path.join(saveDir, componentName + jsxExtension), singleFile);
if (!config.use_typescript) {
let typeDefinitionFile = getTemplate('SingleIcon.d.ts');
typeDefinitionFile = replaceComponentName(typeDefinitionFile, componentName);
fs.writeFileSync(path.join(saveDir, componentName + '.d.ts'), typeDefinitionFile);
}
console.log(`${colors.green('√')} Generated icon "${colors.yellow(iconId)}"`);
});
let iconFile = getTemplate('Icon' + jsxExtension);
iconFile = replaceCases(iconFile, cases);
iconFile = replaceImports(iconFile, imports);
iconFile = replaceExports(iconFile, imports);
if (config.use_typescript) {
iconFile = replaceNames(iconFile, names);
} else {
iconFile = replaceNamesArray(iconFile, names);
let typeDefinitionFile = getTemplate(`Icon.d.ts`);
typeDefinitionFile = replaceExports(typeDefinitionFile, imports);
typeDefinitionFile = replaceNames(typeDefinitionFile, names);
fs.writeFileSync(path.join(saveDir, 'index.d.ts'), typeDefinitionFile);
}
fs.writeFileSync(path.join(saveDir, 'index' + jsxExtension), iconFile);
console.log(`\n${colors.green('√')} All icons have putted into dir: ${colors.green(config.save_dir)}\n`);
};
const generateCase = (data: XmlData['svg']['symbol'][number], baseIdent: number) => {
let template = `\n${whitespace(baseIdent)}<svg viewBox="${data.$.viewBox}" width={size} height={size} style={style} {...rest}>\n`;
for (const domName of Object.keys(data)) {
if (domName === '$') {
continue;
}
if (!domName) {
console.error(colors.red(`Unable to transform dom "${domName}"`));
process.exit(1);
}
const counter = {
colorIndex: 0,
baseIdent,
};
if (data[domName].$) {
template += `${whitespace(baseIdent + 2)}<${domName}${addAttribute(domName, data[domName], counter)}\n${whitespace(baseIdent + 2)}/>\n`;
} else if (Array.isArray(data[domName])) {
data[domName].forEach((sub) => {
template += `${whitespace(baseIdent + 2)}<${domName}${addAttribute(domName, sub, counter)}\n${whitespace(baseIdent + 2)}/>\n`;
});
}
}
template += `${whitespace(baseIdent)}</svg>\n`;
return template;
};
const addAttribute = (domName: string, sub: XmlData['svg']['symbol'][number]['path'][number], counter: { colorIndex: number, baseIdent: number }) => {
let template = '';
if (sub && sub.$) {
if (ATTRIBUTE_FILL_MAP.includes(domName)) {
// Set default color same as in iconfont.cn
// And create placeholder to inject color by user's behavior
sub.$.fill = sub.$.fill || '#333333';
}
for (const attributeName of Object.keys(sub.$)) {
if (attributeName === 'fill') {
template += `\n${whitespace(counter.baseIdent + 4)}${camelCase(attributeName)}={getIconColor(color, ${counter.colorIndex}, '${sub.$[attributeName]}')}`;
counter.colorIndex += 1;
} else {
template += `\n${whitespace(counter.baseIdent + 4)}${camelCase(attributeName)}="${sub.$[attributeName]}"`;
}
}
}
return template;
};