mirror of
https://github.com/iconoir-icons/iconoir
synced 2024-05-17 22:06:42 +02:00
249 lines
6.2 KiB
JavaScript
249 lines
6.2 KiB
JavaScript
import * as svgr from '@svgr/core';
|
|
import * as esbuild from 'esbuild';
|
|
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import {
|
|
generateExport,
|
|
generateImport,
|
|
toImportPath,
|
|
} from '../../lib/import-export.js';
|
|
import { getDts } from '../../lib/ts.js';
|
|
import iconoirContextTemplate, {
|
|
exports as iconoirContextExports,
|
|
} from './resources/context-template.js';
|
|
import { getTemplate as getIconTemplate } from './resources/icon-template.js';
|
|
import { nativeSvgrOptions, svgrOptions } from './resources/svgr-options.js';
|
|
|
|
const outDir = 'dist';
|
|
|
|
const jsTargets = [
|
|
{
|
|
format: 'cjs',
|
|
module: 'commonjs',
|
|
dir: '.',
|
|
ext: 'js',
|
|
dtsExt: 'd.ts',
|
|
},
|
|
{
|
|
format: 'esm',
|
|
module: 'esnext',
|
|
dir: 'esm',
|
|
ext: 'mjs',
|
|
dtsExt: 'd.mts',
|
|
},
|
|
];
|
|
|
|
/** @type {import('esbuild').TransformOptions} */
|
|
const defaultEsbuildOptions = { target: 'es6', minify: true };
|
|
|
|
/** @type {import('typescript').CompilerOptions} */
|
|
const defaultTsOptions = {
|
|
jsx: 'react',
|
|
declaration: true,
|
|
emitDeclarationOnly: true,
|
|
target: 'es6',
|
|
strict: true,
|
|
esModuleInterop: true,
|
|
skipLibCheck: true,
|
|
};
|
|
|
|
export default async (ctx, target) => {
|
|
const localJsTargets = jsTargets.map((jsTarget) => ({
|
|
...jsTarget,
|
|
iconTemplate: getIconTemplate(target.native, jsTarget.ext),
|
|
}));
|
|
|
|
const promises = [];
|
|
|
|
const outPath = path.join(target.path, outDir);
|
|
|
|
// Preparation
|
|
// (needs to run in a separate loop, otherwise leads to uncaught exceptions in case of errors in main loop)
|
|
for (const jsTarget of localJsTargets) {
|
|
jsTarget.path = path.join(outPath, jsTarget.dir);
|
|
|
|
await fs.mkdir(jsTarget.path, { recursive: true });
|
|
|
|
const iconoirContext = iconoirContextTemplate(target.native);
|
|
|
|
jsTarget.iconoirContextPath = path.join(
|
|
jsTarget.path,
|
|
`IconoirContext.${jsTarget.ext}`,
|
|
);
|
|
|
|
await generateJs(
|
|
jsTarget.iconoirContextPath,
|
|
iconoirContext,
|
|
jsTarget.format,
|
|
);
|
|
|
|
const iconoirContextTsxPath = path.join(
|
|
jsTarget.path,
|
|
'IconoirContext.tsx',
|
|
);
|
|
const iconoirContextDtsPath = path.join(
|
|
jsTarget.path,
|
|
`IconoirContext.${jsTarget.dtsExt}`,
|
|
);
|
|
|
|
await generateDts(
|
|
iconoirContextTsxPath,
|
|
iconoirContextDtsPath,
|
|
iconoirContext,
|
|
jsTarget.module,
|
|
);
|
|
|
|
for (const variant of Object.keys(ctx.icons)) {
|
|
jsTarget.path = path.join(outPath, jsTarget.dir);
|
|
|
|
await fs.mkdir(path.join(jsTarget.path, variant), { recursive: true });
|
|
}
|
|
}
|
|
|
|
for (const jsTarget of localJsTargets) {
|
|
const mainIndex = prepareIndex(jsTarget);
|
|
|
|
for (const [variant, icons] of Object.entries(ctx.icons)) {
|
|
const variantIndex = prepareIndex(jsTarget, variant);
|
|
|
|
for (const icon of icons) {
|
|
const mainIndexComponentName =
|
|
variant === ctx.global.defaultVariant
|
|
? icon.pascalName
|
|
: icon.pascalNameVariant;
|
|
|
|
const jsPath = path.join(
|
|
jsTarget.path,
|
|
variant,
|
|
`${icon.pascalName}.${jsTarget.ext}`,
|
|
);
|
|
|
|
mainIndex.add(mainIndexComponentName, jsPath);
|
|
variantIndex.add(icon.pascalName, jsPath);
|
|
|
|
const reactComponent = getReactComponent(
|
|
icon.path,
|
|
target.native,
|
|
jsTarget.iconTemplate,
|
|
);
|
|
|
|
// Only run for first icon, type is same and can be reused for all the others
|
|
if (!jsTarget.iconDts) {
|
|
jsTarget.iconDts = true;
|
|
|
|
// Virtual input path
|
|
const tsxPath = path.join(jsTarget.path, variant, 'icon.tsx');
|
|
|
|
const dtsPath = path.join(jsTarget.path, `icon.${jsTarget.dtsExt}`);
|
|
|
|
const iconDts = generateDts(
|
|
tsxPath,
|
|
dtsPath,
|
|
reactComponent,
|
|
jsTarget.module,
|
|
);
|
|
|
|
promises.push(iconDts);
|
|
}
|
|
|
|
const iconJs = generateJs(jsPath, reactComponent, jsTarget.format);
|
|
|
|
promises.push(iconJs);
|
|
}
|
|
|
|
promises.push(variantIndex.generate());
|
|
}
|
|
|
|
promises.push(mainIndex.generate());
|
|
}
|
|
|
|
return Promise.all(promises);
|
|
};
|
|
|
|
async function getReactComponent(iconPath, native, template) {
|
|
const iconContent = await fs.readFile(iconPath, 'utf8');
|
|
|
|
const options = native ? nativeSvgrOptions : svgrOptions;
|
|
options.template = template;
|
|
|
|
return svgr.transform(iconContent, options);
|
|
}
|
|
|
|
async function generateDts(inputPath, outputPath, input, module) {
|
|
const dts = getDts(inputPath, await input, {
|
|
...defaultTsOptions,
|
|
module,
|
|
});
|
|
|
|
return fs.writeFile(outputPath, dts);
|
|
}
|
|
|
|
async function generateJs(outputPath, input, format) {
|
|
const { code } = await esbuild.transform(await input, {
|
|
...defaultEsbuildOptions,
|
|
loader: 'tsx',
|
|
format,
|
|
});
|
|
|
|
return fs.writeFile(outputPath, code);
|
|
}
|
|
|
|
function prepareIndex(jsTarget, variant) {
|
|
const outputPath = path.join(jsTarget.path, variant ?? '');
|
|
|
|
const iconoirContextPath = toImportPath(
|
|
path.relative(outputPath, jsTarget.iconoirContextPath),
|
|
);
|
|
|
|
const iconoirContext = generateExport(
|
|
iconoirContextExports,
|
|
iconoirContextPath,
|
|
);
|
|
|
|
const content = [iconoirContext];
|
|
|
|
const iconJsPath = toImportPath(
|
|
path.relative(outputPath, path.join(jsTarget.path, `icon.${jsTarget.ext}`)),
|
|
);
|
|
|
|
const iconDtsImport = generateImport('Icon', iconJsPath);
|
|
|
|
const dtsContent = [iconoirContext, iconDtsImport, 'type I = typeof Icon;'];
|
|
|
|
function add(name, iconPath) {
|
|
const iconImportPath = toImportPath(path.relative(outputPath, iconPath));
|
|
|
|
content.push(generateExport(`default as ${name}`, iconImportPath));
|
|
|
|
dtsContent.push(`export declare const ${name}: I;`);
|
|
}
|
|
|
|
function generate() {
|
|
const indexJs = generateIndexJs(
|
|
outputPath,
|
|
content,
|
|
jsTarget.format,
|
|
jsTarget.ext,
|
|
);
|
|
|
|
const indexDts = generateIndexDts(outputPath, dtsContent, jsTarget.dtsExt);
|
|
|
|
return Promise.all([indexJs, indexDts]);
|
|
}
|
|
|
|
return { add, generate };
|
|
}
|
|
|
|
async function generateIndexJs(outputDir, content, format, ext) {
|
|
const { code } = await esbuild.transform(content.join(''), {
|
|
minify: true,
|
|
format,
|
|
});
|
|
|
|
return fs.writeFile(path.join(outputDir, `index.${ext}`), code);
|
|
}
|
|
|
|
async function generateIndexDts(outputDir, content, dtsExt) {
|
|
return fs.writeFile(path.join(outputDir, `index.${dtsExt}`), content);
|
|
}
|