优化
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
import { parse } from '@babel/parser';
|
||||
import traverse from '@babel/traverse';
|
||||
import {
|
||||
isArrayExpression,
|
||||
isConditionalExpression,
|
||||
isIdentifier,
|
||||
isJSXAttribute,
|
||||
isJSXExpressionContainer,
|
||||
isJSXIdentifier,
|
||||
isObjectExpression,
|
||||
isObjectProperty,
|
||||
isStringLiteral,
|
||||
} from '@babel/types';
|
||||
import globby from 'globby';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
import axios from 'axios';
|
||||
|
||||
const PROJECT_ROOT = path.resolve(__dirname, '../../../../../');
|
||||
|
||||
/**
|
||||
* Entry
|
||||
*/
|
||||
(async () => {
|
||||
const start = Date.now();
|
||||
const paths = await globby(['**.tsx'], {
|
||||
cwd: PROJECT_ROOT,
|
||||
});
|
||||
|
||||
console.log(`extract icons from ${paths.length} files...`);
|
||||
|
||||
const res = await Promise.all(
|
||||
paths.map((p) => extractIcons(path.resolve(PROJECT_ROOT, p)))
|
||||
);
|
||||
|
||||
const icons = _.uniq(_.flatten(res)).sort();
|
||||
|
||||
console.log(`extract ${icons.length} icons, usage: ${Date.now() - start}ms`);
|
||||
|
||||
const group = _.mapValues(
|
||||
_.groupBy(icons, (icon) => icon.split(':')[0]),
|
||||
(value) => {
|
||||
return value.map((item) => item.split(':')[1]);
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`fetching remote svg....`);
|
||||
|
||||
const svgs = await Promise.all(
|
||||
_.map(group, (icons, prefix) => {
|
||||
return fetchSvgs(prefix, icons);
|
||||
})
|
||||
);
|
||||
|
||||
const target = path.resolve(__dirname, '../src/icons.json');
|
||||
await fs.writeJSON(target, svgs, { spaces: 2 });
|
||||
|
||||
console.log('DONE! Assets has been write into:', target);
|
||||
})();
|
||||
|
||||
async function extractIcons(filepath: string): Promise<string[]> {
|
||||
const code = await fs.readFile(filepath, 'utf-8');
|
||||
|
||||
const ast = parse(code, {
|
||||
sourceType: 'module',
|
||||
plugins: ['jsx', 'typescript'],
|
||||
});
|
||||
|
||||
const icons = [];
|
||||
|
||||
traverse(ast, {
|
||||
JSXOpeningElement(path) {
|
||||
const name = path.node.name;
|
||||
if (
|
||||
isJSXIdentifier(name) &&
|
||||
['Icon', 'IconBtn', 'LogoLink', 'BaseChatInputButton'].includes(
|
||||
name.name
|
||||
)
|
||||
) {
|
||||
path.node.attributes.forEach((attribute) => {
|
||||
if (isJSXAttribute(attribute) && attribute.name.name === 'icon') {
|
||||
if (isStringLiteral(attribute.value) && attribute.value.value) {
|
||||
icons.push(attribute.value.value);
|
||||
} else if (isJSXExpressionContainer(attribute.value)) {
|
||||
// is icon={...}
|
||||
if (isStringLiteral(attribute.value.expression)) {
|
||||
// is icon={''}
|
||||
icons.push(attribute.value.expression.value);
|
||||
} else if (isConditionalExpression(attribute.value.expression)) {
|
||||
// is icon={boolean ? '' : ''}
|
||||
|
||||
if (isStringLiteral(attribute.value.expression.consequent)) {
|
||||
icons.push(attribute.value.expression.consequent.value);
|
||||
}
|
||||
if (isStringLiteral(attribute.value.expression.alternate)) {
|
||||
icons.push(attribute.value.expression.alternate.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
CallExpression(path) {
|
||||
if (!isIdentifier(path.node.callee)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
['regCustomPanel', 'regPluginPanelAction'].includes(
|
||||
path.node.callee.name
|
||||
)
|
||||
) {
|
||||
path.node.arguments.forEach((argument) => {
|
||||
if (isObjectExpression(argument)) {
|
||||
argument.properties.forEach((property) => {
|
||||
if (
|
||||
isObjectProperty(property) &&
|
||||
isIdentifier(property.key) &&
|
||||
property.key.name === 'icon' &&
|
||||
isStringLiteral(property.value) &&
|
||||
property.value.value // icon maybe empty string in some type
|
||||
) {
|
||||
icons.push(property.value.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (path.node.callee.name === 'regGroupPanel') {
|
||||
path.node.arguments.forEach((argument) => {
|
||||
if (isObjectExpression(argument)) {
|
||||
argument.properties.forEach((property) => {
|
||||
if (
|
||||
isObjectProperty(property) &&
|
||||
isIdentifier(property.key) &&
|
||||
property.key.name === 'menus' &&
|
||||
isArrayExpression(property.value)
|
||||
) {
|
||||
property.value.elements.forEach((element) => {
|
||||
if (isObjectExpression(element)) {
|
||||
element.properties.forEach((property) => {
|
||||
if (
|
||||
isObjectProperty(property) &&
|
||||
isIdentifier(property.key) &&
|
||||
property.key.name === 'icon' &&
|
||||
isStringLiteral(property.value) &&
|
||||
property.value.value // icon maybe empty string in some type
|
||||
) {
|
||||
icons.push(property.value.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function fetchSvgs(
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): Promise<{
|
||||
aliases: any;
|
||||
height: number;
|
||||
width: number;
|
||||
icons: Record<string, { body: string }>;
|
||||
lastModified: number;
|
||||
prefix: string;
|
||||
}> {
|
||||
const { data } = await axios.get(`/${prefix}.json?icons=${icons.join(',')}`, {
|
||||
baseURL: 'https://api.simplesvg.com/', // https://iconify.design/docs/api/#public-api
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user