UNPKG

@chakra-icons/cli

Version:

a tooling for manage everything in @chakra-icons

172 lines (169 loc) 5.69 kB
// src/build.ts import babelGenerator from "@babel/generator"; import * as t from "@babel/types"; import { pascalCase } from "change-case"; import { cli } from "create-chakra-icons"; import degit from "degit"; import * as A from "fp-ts/Array"; import * as E from "fp-ts/Either"; import { flow, pipe } from "fp-ts/function"; import * as O from "fp-ts/Option"; import * as S from "fp-ts/string"; import * as TE from "fp-ts/TaskEither"; import * as fs from "fs/promises"; import * as _glob from "glob"; import * as path from "path"; var metaIconDefault = (name, repository, iconPath, clonePath, sourcePath) => ({ name, repository, iconPath, clonePath, sourcePath, sources: [] }); var prefixWhenNumeric = (prefix) => (n) => /^\d.*$/.test(n) ? `${prefix}${n}` : n; var moduleName = flow(prefixWhenNumeric("I"), pascalCase, S.replace(/[^A-Z0-9]/gi, "")); var hotfixPkgIconNameReplace = [ [ /tabler-icons/i, { "device-game-pad": "device-dpad" // prevent conflict with `device-gamepad` } ] ]; var hotfixName = (metaIcon) => (name) => pipe( hotfixPkgIconNameReplace, A.findFirst(([pattern]) => pattern.test(metaIcon.repository)), O.fold( () => name, ([, maps]) => pipe( maps[name], O.fromNullable, O.getOrElse(() => name) ) ) ); var setSources = (metaIcon) => (beSources) => { const createSource = (sources, svg) => { const { dir, name: _name } = path.parse(svg); const name = pipe(_name, hotfixName(metaIcon), moduleName); const entryPoint = path.join( dir.replace(path.join(metaIcon.clonePath, metaIcon.iconPath), metaIcon.sourcePath), "index.ts" ); const entry = { name, svg, code: path.join(path.dirname(entryPoint), `${name}.tsx`) }; const maybeIcon = sources.find((icon) => S.Eq.equals(icon.entryPoint, entryPoint)); if (maybeIcon) { sources[sources.indexOf(maybeIcon)]?.entries.push(entry); return sources; } return [...sources, { entryPoint, entries: [entry] }]; }; return { ...metaIcon, sources: beSources.reduce((a, b) => createSource(a, b), metaIcon.sources) }; }; var writeFile2 = (file, data) => TE.tryCatch(() => fs.mkdir(path.dirname(file), { recursive: true }).then(() => fs.writeFile(file, data)), E.toError); var glob2 = (target) => TE.tryCatch(() => _glob.glob(target), E.toError); var cloneRepository = (metaIcon) => TE.tryCatch( () => degit(metaIcon.repository, { force: true }).clone(metaIcon.clonePath).then(() => metaIcon), E.toError ); var findSvgs = (metaIcon) => pipe(path.join(metaIcon.clonePath, metaIcon.iconPath, "**", "*.svg"), glob2, TE.map(setSources(metaIcon))); var createIcons = (options) => TE.tryCatch(() => Promise.resolve(cli.main(options)), E.toError); var generateIcons = (metaIcon) => pipe( metaIcon.sources, A.map( ({ entries }) => pipe( entries, A.map(({ name: n, svg: i, code: o }) => createIcons({ n, i, o, ts: true, T: "C", useFilename: true })) ) ), A.flatten, TE.sequenceArray ); var generateExportAllCode = (name) => pipe(`./${name}`, t.stringLiteral, t.exportAllDeclaration, babelGenerator, (b) => b.code); var genrateExportAllNamespace = (alias, source) => babelGenerator( t.exportNamedDeclaration(null, [pipe(alias, t.identifier, t.exportNamespaceSpecifier)], t.stringLiteral(source)) ).code; var generateEntrypointCode = (source) => pipe( source.entries, A.map((s) => generateExportAllCode(s.name)), (arr) => arr.join("\r\n") ); var generateEntrypoint = (metaIcon) => pipe( metaIcon.sources, A.map((a) => writeFile2(a.entryPoint, generateEntrypointCode(a))), TE.sequenceArray ); var generateSnapshot = (options) => (metaIcon) => pipe( options.snapshot, O.fromNullable, O.fold( () => TE.of(metaIcon), (file) => pipe( TE.of(metaIcon), TE.chainFirst((_metaIcon) => writeFile2(file, JSON.stringify(_metaIcon, null, 2))) ) ) ); var generateRootEntryPoint = (metaIcon) => pipe( metaIcon.sources, A.findFirst((source) => S.Eq.equals(source.entryPoint, path.join(metaIcon.sourcePath, "index.ts"))), O.fold( () => [ writeFile2( path.join(metaIcon.sourcePath, "index.ts"), pipe( metaIcon.sources, // eslint-disable-next-line @typescript-eslint/unbound-method A.map((source) => pipe(source.entryPoint, path.dirname, path.basename)), A.map((source) => genrateExportAllNamespace(source, "./".concat(source))), (arrs) => arrs.join("\r\n") ) ) ], () => [] ), TE.sequenceArray ); var buildFlow = flow( // make MetaIcon and cloneRepository TE.chain(cloneRepository), // scan svg in target directory TE.chain(findSvgs), // generated icons (src/*.tsx) in file system TE.chainFirst(generateIcons), // generated index.ts TE.chainFirst(generateEntrypoint), // generated src/index.ts when iconPath is nested TE.chainFirst(generateRootEntryPoint) ); var build = (options) => { const { name, repository, iconPath, clonePath, sourcePath } = options; const metaIcon = metaIconDefault(name, repository, iconPath, clonePath, sourcePath); return pipe( // make `metaIcon` object to TaskEither TE.of(metaIcon), // main flow buildFlow, // when pass `snapshot` in options TE.chainFirst(generateSnapshot(options)) // when pass `entryPoints` in options // it will be make entrypoints.ts for use in tsup.config // TE.chainFirst(generateExportEntrypoints(options)), // it will be update package.json // TE.chainFirst(updatePkgJson(options)), ); }; // src/init.ts var init = (options) => { console.log({ options }); }; export { buildFlow, build, init };