Skip to content

Commit

Permalink
feat: import code
Browse files Browse the repository at this point in the history
  • Loading branch information
gronxb committed Sep 14, 2024
1 parent e6043cd commit 38e2770
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { addIcon } from "../utils//config";
export const add = async (iconName: string) => {
try {
const config = await addIcon(iconName);
await syncIcons(config.icons);
await syncIcons(config);
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
Expand Down
4 changes: 2 additions & 2 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export const init = async () => {
p.confirm({
message: "Would you like to enable TypeScript support?",
}),
path: () =>
outputPath: () =>
p.text({
message: "Specify the directory for storing icons:",
message: "Specify the directory for saving icons:",
placeholder: "assets/icons",
initialValue: "assets/icons",
}),
Expand Down
14 changes: 10 additions & 4 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import path from "path";
import fs from "fs/promises";
import { z } from "zod";
import { getCwd } from "./cwd";
import { uniq } from "./uniq";

export const configSchema = z.object({
typescript: z.boolean(),
path: z.string(),
outputPath: z.string(),
icons: z.array(z.string()),
});

export type Config = z.infer<typeof configSchema>;

export const loadConfig = async () => {
const cwd = getCwd();

Expand All @@ -23,18 +26,21 @@ export const loadConfig = async () => {

export const addIcon = async (iconName: string) => {
const config = await loadConfig();
config.icons.push(iconName);
const updatedIcons = uniq([...config.icons, iconName]);
config.icons = updatedIcons;

return initConfig(config);
};

export const initConfig = async (config: z.infer<typeof configSchema>) => {
export const initConfig = async (config: Config) => {
const cwd = getCwd();

const data = configSchema.parse(config);

await fs.writeFile(
path.join(cwd, "react-native-icons-builder.json"),
JSON.stringify(configSchema.parse(config), null, 2)
JSON.stringify(configSchema.parse(config), null, 2),
"utf8"
);
return data;
};
61 changes: 48 additions & 13 deletions src/utils/generateIcon.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import path from "path";
import fs from "fs/promises";
import { type ModuleItem, parse, print } from "@swc/core";
import { groupIconsByPrefix } from "./groupIconsByPrefix";
import type { Config } from "./config";
import { getCwd } from "./cwd";

export const generateIcon = async (prefix: string, icons: string[]) => {
export const generateIconCode = async (
prefix: string,
icons: string[],
typescript: boolean
) => {
const path = import.meta
.resolve("react-icons")
.replace("file://", "")
.replace("/index.mjs", `/${prefix}/index.mjs`);

const code = await fs.readFile(path, "utf8");
const reactIconsCode = await fs.readFile(path, "utf8");

const ast = await parse(code, {
const ast = await parse(reactIconsCode, {
syntax: "ecmascript",
jsx: true,
});

const svgTagSet = new Set<string>();

function transformStringToIdentifier(moduleItem: ModuleItem): ModuleItem {
function transform(item: any): any {
if (Array.isArray(item)) {
Expand All @@ -27,6 +36,10 @@ export const generateIcon = async (prefix: string, icons: string[]) => {
item.key.value === "tag" &&
item.value.type === "StringLiteral"
) {
const svgTag =
item.value.value.charAt(0).toUpperCase() +
item.value.value.slice(1);
svgTagSet.add(svgTag);
return {
...item,
value: {
Expand All @@ -36,9 +49,7 @@ export const generateIcon = async (prefix: string, icons: string[]) => {
end: item.value.span.end - 2,
},
ctxt: 0,
value:
item.value.value.charAt(0).toUpperCase() +
item.value.value.slice(1),
value: svgTag,
optional: false,
},
};
Expand Down Expand Up @@ -74,17 +85,41 @@ export const generateIcon = async (prefix: string, icons: string[]) => {
};

const outputCode = await print(filteredAst, {});
if (outputCode.code.length === 0) {
// throw new Error(`Icon ${iconName} not found`);
let code = outputCode.code;
if (typescript) {
code = code.replaceAll("(props) ", "(props: IconBaseProps) ");
}
return outputCode.code;
code = `
import { ${[...svgTagSet].join(", ")} } from "react-native-svg"
import { type IconBaseProps, GenIcon } from "./iconBase";
${code}
`;

return {
filename: typescript ? `${prefix}.tsx` : `${prefix}.jsx`,
code,
};
};

const saveIcons = async (
outputPath: string,
filename: string,
code: string
) => {
const cwd = getCwd();
const $outputPath = path.join(cwd, outputPath);
await fs.mkdir($outputPath, { recursive: true });

await fs.writeFile(path.join($outputPath, filename), code, "utf8");
};

export const syncIcons = async (icons: string[]) => {
const groupedIcons = groupIconsByPrefix(icons);
export const syncIcons = async (config: Config) => {
const groupedIcons = groupIconsByPrefix(config.icons);
await Promise.all(
groupedIcons.map(([prefix, icons]) => {
generateIcon(prefix, icons);
groupedIcons.map(async ([prefix, icons]) => {
const data = await generateIconCode(prefix, icons, config.typescript);
await saveIcons(config.outputPath, data.filename, data.code);
})
);
};
3 changes: 3 additions & 0 deletions src/utils/uniq.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const uniq = (arr: string[]) => {
return Array.from(new Set(arr));
};

0 comments on commit 38e2770

Please sign in to comment.