diff --git a/generators/icons/package.json b/generators/icons/package.json index 109ff2c5d..8d6470748 100644 --- a/generators/icons/package.json +++ b/generators/icons/package.json @@ -12,14 +12,14 @@ }, "main": "src/index.ts", "bin": { - "generate-icons": "dist/icons.generator.js" + "generate-icons": "dist/generator.js" }, "files": [ "dist" ], "scripts": { "build": "yarn library build", - "generate-icons": "tsx src/icons.generator.ts", + "generate-icons": "tsx src/generator.ts", "prepack": "yarn run build", "postpack": "rm -rf dist" }, @@ -30,12 +30,12 @@ "@swc/core": "1.6.1", "cheerio": "1.1.2", "clipanion": "4.0.0-rc.4", + "domhandler": "5.0.3", "glob": "11.0.2", "is-svg": "6.1.0" }, "devDependencies": { "@types/node": "22.15.3", - "domhandler": "5.0.3", "tsx": "4.20.5", "typescript": "5.5.4" }, diff --git a/generators/icons/src/commands/base-icons.command.ts b/generators/icons/src/commands/base-icons.command.ts index 41f456a94..1f61e1df0 100644 --- a/generators/icons/src/commands/base-icons.command.ts +++ b/generators/icons/src/commands/base-icons.command.ts @@ -1,6 +1,6 @@ /* eslint-disable n/no-sync */ -import type { ResolvedIconsPath } from '../icons.interfaces.js' +import type { ResolvedIconsPath } from '../interfaces.js' import assert from 'node:assert/strict' import fs from 'node:fs' @@ -49,6 +49,7 @@ export class BaseIconsCommand extends Command { this.resolvePaths() } catch (error) { this.logger.error(error) + process.exitCode = 1 } } } diff --git a/generators/icons/src/commands/generate-icons.command.ts b/generators/icons/src/commands/generate-icons.command.ts index 7af5e650e..9e03d28d1 100644 --- a/generators/icons/src/commands/generate-icons.command.ts +++ b/generators/icons/src/commands/generate-icons.command.ts @@ -1,6 +1,6 @@ /* eslint-disable n/no-sync */ -import type { Replacements } from '../icons.interfaces.js' +import type { Replacements } from '../interfaces.js' import assert from 'node:assert/strict' import { lstatSync } from 'node:fs' @@ -57,6 +57,7 @@ export class GenerateIconsCommand extends BaseIconsCommand { this.logger.info(`Generated into ${outputPath}`) } catch (error) { this.logger.error(error) + process.exitCode = 1 } } } diff --git a/generators/icons/src/commands/generate-replacements.command.ts b/generators/icons/src/commands/generate-replacements.command.ts index 7c33ea222..a83e3b2d6 100644 --- a/generators/icons/src/commands/generate-replacements.command.ts +++ b/generators/icons/src/commands/generate-replacements.command.ts @@ -38,6 +38,7 @@ export class GenerateReplacementsCommand extends BaseIconsCommand { this.logger.info(`Generated into ${outputFilePath}`) } catch (error) { this.logger.error(error) + process.exitCode = 1 } } } diff --git a/generators/icons/src/icons.generator.ts b/generators/icons/src/generator.ts similarity index 100% rename from generators/icons/src/icons.generator.ts rename to generators/icons/src/generator.ts diff --git a/generators/icons/src/icons.interfaces.ts b/generators/icons/src/interfaces.ts similarity index 100% rename from generators/icons/src/icons.interfaces.ts rename to generators/icons/src/interfaces.ts diff --git a/generators/icons/src/replacement-utils/build-replacements/build-replacements.util.ts b/generators/icons/src/replacement-utils/build-replacements/build-replacements.ts similarity index 72% rename from generators/icons/src/replacement-utils/build-replacements/build-replacements.util.ts rename to generators/icons/src/replacement-utils/build-replacements/build-replacements.ts index b7df353d4..cf402d9e9 100644 --- a/generators/icons/src/replacement-utils/build-replacements/build-replacements.util.ts +++ b/generators/icons/src/replacement-utils/build-replacements/build-replacements.ts @@ -1,5 +1,5 @@ -import type { Icon } from '../../icons.interfaces.js' -import type { Replacements } from '../../icons.interfaces.js' +import type { Icon } from '../../interfaces.js' +import type { Replacements } from '../../interfaces.js' import { createReplacementIconColors } from '../create-replacement-icon-colors/index.js' import { createReplacements } from '../create-replacements/index.js' diff --git a/generators/icons/src/replacement-utils/build-replacements/index.ts b/generators/icons/src/replacement-utils/build-replacements/index.ts index daeaeb6ec..fee3eaded 100644 --- a/generators/icons/src/replacement-utils/build-replacements/index.ts +++ b/generators/icons/src/replacement-utils/build-replacements/index.ts @@ -1 +1 @@ -export * from './build-replacements.util.js' +export * from './build-replacements.js' diff --git a/generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.constants.ts b/generators/icons/src/replacement-utils/create-replacement-icon-colors/constants.ts similarity index 100% rename from generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.constants.ts rename to generators/icons/src/replacement-utils/create-replacement-icon-colors/constants.ts diff --git a/generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.util.ts b/generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.ts similarity index 76% rename from generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.util.ts rename to generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.ts index f0a4dd430..3554030ff 100644 --- a/generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.util.ts +++ b/generators/icons/src/replacement-utils/create-replacement-icon-colors/create-replacement-icon-colors.ts @@ -1,9 +1,9 @@ -import type { Icon } from '../../icons.interfaces.js' -import type { ReplacementIconColors } from '../../icons.interfaces.js' +import type { Icon } from '../../interfaces.js' +import type { ReplacementIconColors } from '../../interfaces.js' import { compileIconJsx } from '../../svgr-utils/index.js' import { getSvgColors } from '../../svgr-utils/index.js' -import { getSvgColorsOptions } from './create-replacement-icon-colors.constants.js' +import { getSvgColorsOptions } from './constants.js' export const createReplacementIconColors = async ( icons: Array diff --git a/generators/icons/src/replacement-utils/create-replacement-icon-colors/index.ts b/generators/icons/src/replacement-utils/create-replacement-icon-colors/index.ts index 775024311..a1a0de194 100644 --- a/generators/icons/src/replacement-utils/create-replacement-icon-colors/index.ts +++ b/generators/icons/src/replacement-utils/create-replacement-icon-colors/index.ts @@ -1 +1 @@ -export * from './create-replacement-icon-colors.util.js' +export * from './create-replacement-icon-colors.js' diff --git a/generators/icons/src/replacement-utils/create-replacements/create-replacements.util.cts b/generators/icons/src/replacement-utils/create-replacements/create-replacements.cts similarity index 100% rename from generators/icons/src/replacement-utils/create-replacements/create-replacements.util.cts rename to generators/icons/src/replacement-utils/create-replacements/create-replacements.cts diff --git a/generators/icons/src/replacement-utils/create-replacements/create-replacements.util.ts b/generators/icons/src/replacement-utils/create-replacements/create-replacements.ts similarity index 81% rename from generators/icons/src/replacement-utils/create-replacements/create-replacements.util.ts rename to generators/icons/src/replacement-utils/create-replacements/create-replacements.ts index 269dabd4c..230409b4d 100644 --- a/generators/icons/src/replacement-utils/create-replacements/create-replacements.util.ts +++ b/generators/icons/src/replacement-utils/create-replacements/create-replacements.ts @@ -1,5 +1,5 @@ -import type { Replacements } from '../../icons.interfaces.js' -import type { ReplacementIconColors } from '../../icons.interfaces.js' +import type { Replacements } from '../../interfaces.js' +import type { ReplacementIconColors } from '../../interfaces.js' import { getColorReplacement } from '../get-color-replacement/index.js' diff --git a/generators/icons/src/replacement-utils/create-replacements/index.cts b/generators/icons/src/replacement-utils/create-replacements/index.cts index 79fe819c3..40fe4a3a5 100644 --- a/generators/icons/src/replacement-utils/create-replacements/index.cts +++ b/generators/icons/src/replacement-utils/create-replacements/index.cts @@ -1 +1 @@ -export * from './create-replacements.util.cjs' +export * from './create-replacements.cjs' diff --git a/generators/icons/src/replacement-utils/create-replacements/index.ts b/generators/icons/src/replacement-utils/create-replacements/index.ts index 7763a0ef7..d8303f53a 100644 --- a/generators/icons/src/replacement-utils/create-replacements/index.ts +++ b/generators/icons/src/replacement-utils/create-replacements/index.ts @@ -1 +1 @@ -export * from './create-replacements.util.js' +export * from './create-replacements.js' diff --git a/generators/icons/src/replacement-utils/create-replacements/tests/create-replacements.test.interfaces.ts b/generators/icons/src/replacement-utils/create-replacements/tests/create-replacements.test.interfaces.ts index 4d73cf9a2..455d83b45 100644 --- a/generators/icons/src/replacement-utils/create-replacements/tests/create-replacements.test.interfaces.ts +++ b/generators/icons/src/replacement-utils/create-replacements/tests/create-replacements.test.interfaces.ts @@ -1,4 +1,4 @@ -import type { Replacements } from '../../../icons.interfaces.js' +import type { Replacements } from '../../../interfaces.js' export interface TestCase { replacementIcons: Record | string> diff --git a/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.util.cts b/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.cts similarity index 100% rename from generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.util.cts rename to generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.cts diff --git a/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.util.ts b/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.ts similarity index 57% rename from generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.util.ts rename to generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.ts index 2cc1fb56b..e6edca79a 100644 --- a/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.util.ts +++ b/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.ts @@ -1,4 +1,4 @@ -import type { GetColorReplacement } from './get-color-replacement.interfaces.js' +import type { GetColorReplacement } from './interfaces.js' export const getColorReplacement: GetColorReplacement = (options) => ({ [options.color]: `currentColor`, diff --git a/generators/icons/src/replacement-utils/get-color-replacement/index.cts b/generators/icons/src/replacement-utils/get-color-replacement/index.cts index e3a4de6fa..db67688e4 100644 --- a/generators/icons/src/replacement-utils/get-color-replacement/index.cts +++ b/generators/icons/src/replacement-utils/get-color-replacement/index.cts @@ -1 +1 @@ -export * from './get-color-replacement.util.cjs' +export * from './get-color-replacement.cjs' diff --git a/generators/icons/src/replacement-utils/get-color-replacement/index.ts b/generators/icons/src/replacement-utils/get-color-replacement/index.ts index 9178ae1f4..86b920d9b 100644 --- a/generators/icons/src/replacement-utils/get-color-replacement/index.ts +++ b/generators/icons/src/replacement-utils/get-color-replacement/index.ts @@ -1 +1 @@ -export * from './get-color-replacement.util.js' +export * from './get-color-replacement.js' diff --git a/generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.interfaces.ts b/generators/icons/src/replacement-utils/get-color-replacement/interfaces.ts similarity index 100% rename from generators/icons/src/replacement-utils/get-color-replacement/get-color-replacement.interfaces.ts rename to generators/icons/src/replacement-utils/get-color-replacement/interfaces.ts diff --git a/generators/icons/src/replacement-utils/write-replacements-file/index.ts b/generators/icons/src/replacement-utils/write-replacements-file/index.ts index d988a0be8..b384e9e5e 100644 --- a/generators/icons/src/replacement-utils/write-replacements-file/index.ts +++ b/generators/icons/src/replacement-utils/write-replacements-file/index.ts @@ -1 +1 @@ -export * from './write-replacements-file.util.js' +export * from './write-replacements-file.js' diff --git a/generators/icons/src/replacement-utils/write-replacements-file/write-replacements-file.util.ts b/generators/icons/src/replacement-utils/write-replacements-file/write-replacements-file.ts similarity index 88% rename from generators/icons/src/replacement-utils/write-replacements-file/write-replacements-file.util.ts rename to generators/icons/src/replacement-utils/write-replacements-file/write-replacements-file.ts index d4307333f..74f883edc 100644 --- a/generators/icons/src/replacement-utils/write-replacements-file/write-replacements-file.util.ts +++ b/generators/icons/src/replacement-utils/write-replacements-file/write-replacements-file.ts @@ -1,6 +1,6 @@ /* eslint-disable n/no-sync */ -import type { Replacements } from '../../icons.interfaces.js' +import type { Replacements } from '../../interfaces.js' import { writeFileSync } from 'node:fs' diff --git a/generators/icons/src/svgr-utils/build-svgr.util.ts b/generators/icons/src/svgr-utils/build-svgr.ts similarity index 64% rename from generators/icons/src/svgr-utils/build-svgr.util.ts rename to generators/icons/src/svgr-utils/build-svgr.ts index 805a87e6e..c05321f76 100644 --- a/generators/icons/src/svgr-utils/build-svgr.util.ts +++ b/generators/icons/src/svgr-utils/build-svgr.ts @@ -1,8 +1,8 @@ -import type { Replacements } from '../icons.interfaces.js' +import type { Replacements } from '../interfaces.js' import { compileIcons } from './compile-icons/index.js' -import { discoverIcons } from './discover-icons.util.js' -import { writeCompiledIcons } from './write-compiled-icons.util.js' +import { discoverIcons } from './discover-icons.js' +import { writeCompiledIcons } from './write-compiled-icons.js' export const buildSvgr = async ( iconsPath: string, diff --git a/generators/icons/src/svgr-utils/compile-icons/compile-icons.constants.ts b/generators/icons/src/svgr-utils/compile-icons/compile-icons.constants.ts deleted file mode 100644 index 55edb097c..000000000 --- a/generators/icons/src/svgr-utils/compile-icons/compile-icons.constants.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Config } from '@svgr/core' - -import { svgrTemplate } from './compile-icons.template.js' - -export const MASK_ID_PATTERN = /mask0/g -export const PROPS_SPREAD_FROM = '...props' -export const PROPS_SPREAD_TO = '...otherProps' - -export const FIFTY_PLUS_PATTERN = '50+' -export const FIFTY_PLUS_REPLACEMENT = 'FiftyPlus' - -export const svgrTransformConfig: Config = { - icon: true, - typescript: true, - template: svgrTemplate, - plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx', '@svgr/plugin-prettier'], - svgProps: { - className: `{clsx(className, String(otherProps.className || ''))}`, - style: '{iconStyle}', - }, -} diff --git a/generators/icons/src/svgr-utils/compile-icons/constants.ts b/generators/icons/src/svgr-utils/compile-icons/constants.ts new file mode 100644 index 000000000..7dc94e773 --- /dev/null +++ b/generators/icons/src/svgr-utils/compile-icons/constants.ts @@ -0,0 +1,54 @@ +import type { Config } from '@svgr/core' + +import type { SvgrPlugin } from './interfaces.js' +import type { SvgrPluginModule } from './interfaces.js' + +import { createRequire } from 'node:module' + +import { svgrTemplate } from './template.js' + +const svgrCorePackageName = '@svgr/core/package.json' + +const svgoPluginName = '@svgr/plugin-svgo' + +const jsxPluginName = '@svgr/plugin-jsx' + +const prettierPluginName = '@svgr/plugin-prettier' + +const require = createRequire(import.meta.url) + +const svgrRequire = createRequire(require.resolve(svgrCorePackageName)) + +const loadSvgrPlugin = (pluginName: string): SvgrPlugin => { + const plugin = svgrRequire(pluginName) as SvgrPlugin | SvgrPluginModule + + if (typeof plugin === 'object' && 'default' in plugin && plugin.default) { + return plugin.default + } + + return plugin as SvgrPlugin +} + +const svgrTransformPlugins = [ + loadSvgrPlugin(svgoPluginName), + loadSvgrPlugin(jsxPluginName), + loadSvgrPlugin(prettierPluginName), +] + +export const MASK_ID_PATTERN = /mask0/g +export const PROPS_SPREAD_FROM = '...props' +export const PROPS_SPREAD_TO = '...otherProps' + +export const FIFTY_PLUS_PATTERN = '50+' +export const FIFTY_PLUS_REPLACEMENT = 'FiftyPlus' + +export const svgrTransformConfig: Config = { + icon: true, + typescript: true, + template: svgrTemplate, + plugins: svgrTransformPlugins, + svgProps: { + className: `{clsx(className, String(otherProps.className || ''))}`, + style: '{iconStyle}', + }, +} diff --git a/generators/icons/src/svgr-utils/compile-icons/compile-icon-jsx.util.ts b/generators/icons/src/svgr-utils/compile-icons/icon-jsx.ts similarity index 57% rename from generators/icons/src/svgr-utils/compile-icons/compile-icon-jsx.util.ts rename to generators/icons/src/svgr-utils/compile-icons/icon-jsx.ts index 3fcdf6008..9fa0c0777 100644 --- a/generators/icons/src/svgr-utils/compile-icons/compile-icon-jsx.util.ts +++ b/generators/icons/src/svgr-utils/compile-icons/icon-jsx.ts @@ -1,9 +1,9 @@ -import type { Icon } from '../../icons.interfaces.js' +import type { Icon } from '../../interfaces.js' import { transform } from '@svgr/core' -import { MASK_ID_PATTERN } from './compile-icons.constants.js' -import { svgrTransformConfig } from './compile-icons.constants.js' +import { MASK_ID_PATTERN } from './constants.js' +import { svgrTransformConfig } from './constants.js' export const compileIconJsx = async (icon: Icon): Promise => transform(icon.source.replace(MASK_ID_PATTERN, icon.name), { diff --git a/generators/icons/src/svgr-utils/compile-icons/compile-icons.util.ts b/generators/icons/src/svgr-utils/compile-icons/icons.ts similarity index 55% rename from generators/icons/src/svgr-utils/compile-icons/compile-icons.util.ts rename to generators/icons/src/svgr-utils/compile-icons/icons.ts index 4764f2b10..a732c26cd 100644 --- a/generators/icons/src/svgr-utils/compile-icons/compile-icons.util.ts +++ b/generators/icons/src/svgr-utils/compile-icons/icons.ts @@ -1,15 +1,15 @@ -import type { Icon } from '../../icons.interfaces.js' -import type { Replacements } from '../../icons.interfaces.js' -import type { Source } from '../../icons.interfaces.js' +import type { Icon } from '../../interfaces.js' +import type { Replacements } from '../../interfaces.js' +import type { Source } from '../../interfaces.js' import { transform } from '@svgr/core' -import { MASK_ID_PATTERN } from './compile-icons.constants.js' -import { PROPS_SPREAD_FROM } from './compile-icons.constants.js' -import { PROPS_SPREAD_TO } from './compile-icons.constants.js' -import { FIFTY_PLUS_PATTERN } from './compile-icons.constants.js' -import { FIFTY_PLUS_REPLACEMENT } from './compile-icons.constants.js' -import { svgrTransformConfig } from './compile-icons.constants.js' +import { MASK_ID_PATTERN } from './constants.js' +import { PROPS_SPREAD_FROM } from './constants.js' +import { PROPS_SPREAD_TO } from './constants.js' +import { FIFTY_PLUS_PATTERN } from './constants.js' +import { FIFTY_PLUS_REPLACEMENT } from './constants.js' +import { svgrTransformConfig } from './constants.js' export const compileIcons = async ( icons: Array, diff --git a/generators/icons/src/svgr-utils/compile-icons/index.ts b/generators/icons/src/svgr-utils/compile-icons/index.ts index c5c923fb1..d3871faed 100644 --- a/generators/icons/src/svgr-utils/compile-icons/index.ts +++ b/generators/icons/src/svgr-utils/compile-icons/index.ts @@ -1,3 +1,3 @@ -export * from './compile-icon-jsx.util.js' -export * from './compile-icons.template.js' -export * from './compile-icons.util.js' +export * from './icon-jsx.js' +export * from './icons.js' +export * from './template.js' diff --git a/generators/icons/src/svgr-utils/compile-icons/interfaces.ts b/generators/icons/src/svgr-utils/compile-icons/interfaces.ts new file mode 100644 index 000000000..d68e95b68 --- /dev/null +++ b/generators/icons/src/svgr-utils/compile-icons/interfaces.ts @@ -0,0 +1,7 @@ +import type { Config } from '@svgr/core' + +export type SvgrPlugin = NonNullable[number] + +export interface SvgrPluginModule { + default?: SvgrPlugin +} diff --git a/generators/icons/src/svgr-utils/compile-icons/compile-icons.template.ts b/generators/icons/src/svgr-utils/compile-icons/template.ts similarity index 100% rename from generators/icons/src/svgr-utils/compile-icons/compile-icons.template.ts rename to generators/icons/src/svgr-utils/compile-icons/template.ts diff --git a/generators/icons/src/svgr-utils/discover-icons.util.ts b/generators/icons/src/svgr-utils/discover-icons.ts similarity index 91% rename from generators/icons/src/svgr-utils/discover-icons.util.ts rename to generators/icons/src/svgr-utils/discover-icons.ts index 535221359..39c2459d3 100644 --- a/generators/icons/src/svgr-utils/discover-icons.util.ts +++ b/generators/icons/src/svgr-utils/discover-icons.ts @@ -1,6 +1,6 @@ /* eslint-disable n/no-sync */ -import type { Icon } from '../icons.interfaces.js' +import type { Icon } from '../interfaces.js' import fs from 'node:fs' diff --git a/generators/icons/src/svgr-utils/get-svg-colors/constants.ts b/generators/icons/src/svgr-utils/get-svg-colors/constants.ts new file mode 100644 index 000000000..e696588aa --- /dev/null +++ b/generators/icons/src/svgr-utils/get-svg-colors/constants.ts @@ -0,0 +1 @@ +export const styleColorAttributeKey = 'style' diff --git a/generators/icons/src/svgr-utils/get-svg-colors/extract-color-from-element.helper.ts b/generators/icons/src/svgr-utils/get-svg-colors/extract-color-from-element.ts similarity index 63% rename from generators/icons/src/svgr-utils/get-svg-colors/extract-color-from-element.helper.ts rename to generators/icons/src/svgr-utils/get-svg-colors/extract-color-from-element.ts index 851451655..1c320d02c 100644 --- a/generators/icons/src/svgr-utils/get-svg-colors/extract-color-from-element.helper.ts +++ b/generators/icons/src/svgr-utils/get-svg-colors/extract-color-from-element.ts @@ -1,9 +1,9 @@ -import type { CheerioAPI } from 'cheerio' -import type { AnyNode } from 'domhandler' +import type { CheerioAPI } from 'cheerio/slim' +import type { AnyNode } from 'domhandler' -import type { GetSvgColorsOptions } from './get-svg-colors.interfaces.js' +import type { GetSvgColorsOptions } from './interfaces.js' -import { STYLE_COLOR_ATTRIBUTE_KEY } from './get-svg-colors.constants.js' +import { styleColorAttributeKey } from './constants.js' export const extractColorFromElement = ( cheerio: CheerioAPI, @@ -19,7 +19,7 @@ export const extractColorFromElement = ( colors.add(value) } - if (name === STYLE_COLOR_ATTRIBUTE_KEY) { + if (name === styleColorAttributeKey) { options.colorAttributes?.forEach((colorAttribute) => { colors.add(cheerio(element).css(colorAttribute) || '') }) diff --git a/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.constants.ts b/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.constants.ts deleted file mode 100644 index 81dee4055..000000000 --- a/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const STYLE_COLOR_ATTRIBUTE_KEY = 'style' diff --git a/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.util.ts b/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.ts similarity index 71% rename from generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.util.ts rename to generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.ts index 935628d59..51a5bdd8b 100644 --- a/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.util.ts +++ b/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.ts @@ -1,9 +1,9 @@ -import type { GetSvgColorsOptions } from './get-svg-colors.interfaces.js' +import type { GetSvgColorsOptions } from './interfaces.js' -import { load } from 'cheerio' +import { load } from 'cheerio/slim' -import { extractColorFromElement } from './extract-color-from-element.helper.js' -import { validateColor } from './validate-color.helper.js' +import { extractColorFromElement } from './extract-color-from-element.js' +import { validateColor } from './helpers/validate-color.js' export const getSvgColors = (source: string, options: GetSvgColorsOptions = {}): Array => { const colors = new Set() diff --git a/generators/icons/src/svgr-utils/get-svg-colors/validate-color.helper.ts b/generators/icons/src/svgr-utils/get-svg-colors/helpers/validate-color.ts similarity index 75% rename from generators/icons/src/svgr-utils/get-svg-colors/validate-color.helper.ts rename to generators/icons/src/svgr-utils/get-svg-colors/helpers/validate-color.ts index 03a673ae9..8578f0ffe 100644 --- a/generators/icons/src/svgr-utils/get-svg-colors/validate-color.helper.ts +++ b/generators/icons/src/svgr-utils/get-svg-colors/helpers/validate-color.ts @@ -1,4 +1,4 @@ -import type { GetSvgColorsOptions } from './get-svg-colors.interfaces.js' +import type { GetSvgColorsOptions } from '../interfaces.js' export const validateColor = (color: string, options: GetSvgColorsOptions): boolean => { if (!color) { diff --git a/generators/icons/src/svgr-utils/get-svg-colors/index.ts b/generators/icons/src/svgr-utils/get-svg-colors/index.ts index bed5362ce..e416e19bc 100644 --- a/generators/icons/src/svgr-utils/get-svg-colors/index.ts +++ b/generators/icons/src/svgr-utils/get-svg-colors/index.ts @@ -1,2 +1,2 @@ -export * from './get-svg-colors.util.js' -export type * from './get-svg-colors.interfaces.js' +export * from './get-svg-colors.js' +export type * from './interfaces.js' diff --git a/generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.interfaces.ts b/generators/icons/src/svgr-utils/get-svg-colors/interfaces.ts similarity index 100% rename from generators/icons/src/svgr-utils/get-svg-colors/get-svg-colors.interfaces.ts rename to generators/icons/src/svgr-utils/get-svg-colors/interfaces.ts diff --git a/generators/icons/src/svgr-utils/index.ts b/generators/icons/src/svgr-utils/index.ts index 1ac2b7a22..32e3c4966 100644 --- a/generators/icons/src/svgr-utils/index.ts +++ b/generators/icons/src/svgr-utils/index.ts @@ -1,4 +1,4 @@ -export * from './build-svgr.util.js' +export * from './build-svgr.js' export * from './compile-icons/index.js' -export * from './discover-icons.util.js' +export * from './discover-icons.js' export * from './get-svg-colors/index.js' diff --git a/generators/icons/src/svgr-utils/write-compiled-icons.util.ts b/generators/icons/src/svgr-utils/write-compiled-icons.ts similarity index 95% rename from generators/icons/src/svgr-utils/write-compiled-icons.util.ts rename to generators/icons/src/svgr-utils/write-compiled-icons.ts index a90821009..2a26363e5 100644 --- a/generators/icons/src/svgr-utils/write-compiled-icons.util.ts +++ b/generators/icons/src/svgr-utils/write-compiled-icons.ts @@ -1,6 +1,6 @@ /* eslint-disable n/no-sync */ -import type { Source } from '../icons.interfaces.js' +import type { Source } from '../interfaces.js' import fs from 'node:fs' import path from 'node:path' diff --git a/ui-admin/icons/lib/generated/check/cli.ts b/ui-admin/icons/lib/generated/check/cli.ts new file mode 100644 index 000000000..55af9aaab --- /dev/null +++ b/ui-admin/icons/lib/generated/check/cli.ts @@ -0,0 +1,13 @@ +import { checkSuccessMessage } from './constants.js' +import { outputLineBreak } from './constants.js' +import { checkGenerated } from './index.js' + +try { + await checkGenerated() + process.stdout.write(`${checkSuccessMessage}${outputLineBreak}`) +} catch (error) { + const errorMessage = error instanceof Error ? (error.stack ?? error.message) : String(error) + + process.stderr.write(`${errorMessage}${outputLineBreak}`) + process.exitCode = 1 +} diff --git a/ui-admin/icons/lib/generated/check/command/interfaces.ts b/ui-admin/icons/lib/generated/check/command/interfaces.ts new file mode 100644 index 000000000..1fa977d90 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/command/interfaces.ts @@ -0,0 +1,3 @@ +export interface CommandOptions { + cwd?: string +} diff --git a/ui-admin/icons/lib/generated/check/command/run.ts b/ui-admin/icons/lib/generated/check/command/run.ts new file mode 100644 index 000000000..3f11aed21 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/command/run.ts @@ -0,0 +1,27 @@ +import type { CommandOptions } from './interfaces.js' + +import { spawn } from 'node:child_process' + +import { CommandFailedError } from '../errors/command-failed.js' + +export const runCommand = async ( + command: string, + args: Array, + options: CommandOptions = {} +): Promise => { + await new Promise((resolve, reject) => { + const childProcess = spawn(command, args, { cwd: options.cwd, stdio: 'inherit' }) + + childProcess.on('error', reject) + + childProcess.on('close', (exitCode) => { + if (exitCode === 0) { + resolve() + + return + } + + reject(new CommandFailedError(command, args, exitCode)) + }) + }) +} diff --git a/ui-admin/icons/lib/generated/check/constants.ts b/ui-admin/icons/lib/generated/check/constants.ts new file mode 100644 index 000000000..57e690266 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/constants.ts @@ -0,0 +1,45 @@ +import { dirname } from 'node:path' +import { resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +const scriptDirectory = dirname(fileURLToPath(import.meta.url)) + +export const packageRootPath = resolve(scriptDirectory, '../../..') + +export const workspaceRootPath = resolve(packageRootPath, '../..') + +export const sourceIconsPath = resolve(packageRootPath, 'src/icons') + +export const sourceReplacementsPath = resolve(packageRootPath, 'src/replacements.ts') + +export const sourceSvgPath = resolve(packageRootPath, 'svg') + +export const temporaryDirectoryPrefix = '.atls-ui-admin-icons-' + +export const generatedIconsDirectoryName = 'icons' + +export const generatedReplacementsDirectoryName = 'replacements' + +export const replacementsFileName = 'replacements.ts' + +export const yarnCommand = 'yarn' + +export const workspaceArgument = 'workspace' + +export const iconsGeneratorWorkspace = '@atls-ui-generators/icons' + +export const generateIconsCommand = 'generate-icons' + +export const generateReplacementsCommand = 'replacements' + +export const formatCommand = 'format' + +export const iconsPathArgument = '-i' + +export const replacementsPathArgument = '-r' + +export const relativePathSeparator = '/' + +export const outputLineBreak = '\n' + +export const checkSuccessMessage = 'Generated icons are up to date' diff --git a/ui-admin/icons/lib/generated/check/drift/directory.ts b/ui-admin/icons/lib/generated/check/drift/directory.ts new file mode 100644 index 000000000..9be2bbe2f --- /dev/null +++ b/ui-admin/icons/lib/generated/check/drift/directory.ts @@ -0,0 +1,83 @@ +import type { DirectoryComparisonOptions } from './interfaces.js' +import type { FileDrift } from './interfaces.js' + +import { readdir } from 'node:fs/promises' +import { join } from 'node:path' +import { sep } from 'node:path' + +import { relativePathSeparator } from '../constants.js' +import { hasFileDrift } from './file.js' +import { fileDriftStates } from './interfaces.js' + +const collectFiles = async (directoryPath: string, currentPath = ''): Promise> => { + const entries = await readdir(join(directoryPath, currentPath), { withFileTypes: true }) + const files = await Promise.all( + entries.map(async (entry) => { + const entryPath = currentPath ? join(currentPath, entry.name) : entry.name + + if (entry.isDirectory()) { + return collectFiles(directoryPath, entryPath) + } + + if (entry.isFile()) { + return [entryPath.split(sep).join(relativePathSeparator)] + } + + return [] + }) + ) + + return files.flat().sort((pathA, pathB) => pathA.localeCompare(pathB)) +} + +export const compareDirectories = async ({ + actualPath, + expectedPath, +}: DirectoryComparisonOptions): Promise> => { + const expectedFiles = new Set(await collectFiles(expectedPath)) + const actualFiles = new Set(await collectFiles(actualPath)) + const relativePaths = [...new Set([...expectedFiles, ...actualFiles])].sort((pathA, pathB) => + pathA.localeCompare(pathB)) + + const outdatedFiles = await Promise.all( + relativePaths.map(async (relativePath) => { + const expectedFilePath = join(expectedPath, relativePath) + const actualFilePath = join(actualPath, relativePath) + + if (!expectedFiles.has(relativePath)) { + return [ + { + actualPath: actualFilePath, + state: fileDriftStates.unexpected, + relativePath, + }, + ] + } + + if (!actualFiles.has(relativePath)) { + return [ + { + expectedPath: expectedFilePath, + state: fileDriftStates.missing, + relativePath, + }, + ] + } + + if (await hasFileDrift(expectedFilePath, actualFilePath)) { + return [ + { + actualPath: actualFilePath, + expectedPath: expectedFilePath, + state: fileDriftStates.different, + relativePath, + }, + ] + } + + return [] + }) + ) + + return outdatedFiles.flat() +} diff --git a/ui-admin/icons/lib/generated/check/drift/file.ts b/ui-admin/icons/lib/generated/check/drift/file.ts new file mode 100644 index 000000000..513373f43 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/drift/file.ts @@ -0,0 +1,60 @@ +import type { FileDrift } from './interfaces.js' + +import { readFile } from 'node:fs/promises' +import { stat } from 'node:fs/promises' +import { basename } from 'node:path' + +import { fileDriftStates } from './interfaces.js' + +const isFile = async (targetPath: string): Promise => { + try { + return (await stat(targetPath)).isFile() + } catch { + return false + } +} + +export const hasFileDrift = async (expectedPath: string, actualPath: string): Promise => + !(await readFile(expectedPath)).equals(await readFile(actualPath)) + +export const compareFiles = async ( + expectedPath: string, + actualPath: string +): Promise> => { + const relativePath = basename(actualPath) + const hasExpectedFile = await isFile(expectedPath) + const hasActualFile = await isFile(actualPath) + + if (!hasExpectedFile) { + return [ + { + actualPath, + state: fileDriftStates.unexpected, + relativePath, + }, + ] + } + + if (!hasActualFile) { + return [ + { + expectedPath, + state: fileDriftStates.missing, + relativePath, + }, + ] + } + + if (await hasFileDrift(expectedPath, actualPath)) { + return [ + { + actualPath, + expectedPath, + state: fileDriftStates.different, + relativePath, + }, + ] + } + + return [] +} diff --git a/ui-admin/icons/lib/generated/check/drift/interfaces.ts b/ui-admin/icons/lib/generated/check/drift/interfaces.ts new file mode 100644 index 000000000..8b63d80a1 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/drift/interfaces.ts @@ -0,0 +1,19 @@ +export const fileDriftStates = { + different: 'different', + missing: 'missing', + unexpected: 'unexpected', +} as const + +export type FileDriftState = (typeof fileDriftStates)[keyof typeof fileDriftStates] + +export interface FileDrift { + actualPath?: string + expectedPath?: string + relativePath: string + state: FileDriftState +} + +export interface DirectoryComparisonOptions { + actualPath: string + expectedPath: string +} diff --git a/ui-admin/icons/lib/generated/check/errors/codes.ts b/ui-admin/icons/lib/generated/check/errors/codes.ts new file mode 100644 index 000000000..2e6e17838 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/codes.ts @@ -0,0 +1,8 @@ +export const generatedErrorCodes = { + commandFailed: 'generated.command_failed', + directoryRequired: 'generated.directory_required', + fileRequired: 'generated.file_required', + filesOutdated: 'generated.files_outdated', +} as const + +export type GeneratedErrorCode = (typeof generatedErrorCodes)[keyof typeof generatedErrorCodes] diff --git a/ui-admin/icons/lib/generated/check/errors/command-failed.ts b/ui-admin/icons/lib/generated/check/errors/command-failed.ts new file mode 100644 index 000000000..258875a11 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/command-failed.ts @@ -0,0 +1,22 @@ +import { GeneratedError } from './generated.js' +import { generatedErrorCodes } from './codes.js' +import { commandFailedMessage } from './messages.js' + +export class CommandFailedError extends GeneratedError { + readonly args: Array + + readonly command: string + + readonly exitCode: number | null + + constructor(command: string, args: Array, exitCode: number | null) { + super( + generatedErrorCodes.commandFailed, + `${commandFailedMessage}: ${command} ${args.join(' ')} (${exitCode})` + ) + + this.args = args + this.command = command + this.exitCode = exitCode + } +} diff --git a/ui-admin/icons/lib/generated/check/errors/directory-required.ts b/ui-admin/icons/lib/generated/check/errors/directory-required.ts new file mode 100644 index 000000000..756590af1 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/directory-required.ts @@ -0,0 +1,13 @@ +import { GeneratedError } from './generated.js' +import { generatedErrorCodes } from './codes.js' +import { directoryRequiredMessage } from './messages.js' + +export class DirectoryRequiredError extends GeneratedError { + readonly path: string + + constructor(targetPath: string) { + super(generatedErrorCodes.directoryRequired, `${directoryRequiredMessage}: ${targetPath}`) + + this.path = targetPath + } +} diff --git a/ui-admin/icons/lib/generated/check/errors/file-required.ts b/ui-admin/icons/lib/generated/check/errors/file-required.ts new file mode 100644 index 000000000..232e271c8 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/file-required.ts @@ -0,0 +1,13 @@ +import { GeneratedError } from './generated.js' +import { generatedErrorCodes } from './codes.js' +import { fileRequiredMessage } from './messages.js' + +export class FileRequiredError extends GeneratedError { + readonly path: string + + constructor(targetPath: string) { + super(generatedErrorCodes.fileRequired, `${fileRequiredMessage}: ${targetPath}`) + + this.path = targetPath + } +} diff --git a/ui-admin/icons/lib/generated/check/errors/files-outdated.ts b/ui-admin/icons/lib/generated/check/errors/files-outdated.ts new file mode 100644 index 000000000..47ecdb507 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/files-outdated.ts @@ -0,0 +1,22 @@ +import type { FileDrift } from '../drift/interfaces.js' + +import { GeneratedError } from './generated.js' +import { generatedErrorCodes } from './codes.js' +import { fileDriftStateMessages } from './messages.js' +import { filesOutdatedMessage } from './messages.js' + +const formatFile = (file: FileDrift): string => + `${file.relativePath}: ${fileDriftStateMessages[file.state]}` + +export class FilesOutdatedError extends GeneratedError { + readonly files: Array + + constructor(files: Array) { + super( + generatedErrorCodes.filesOutdated, + [filesOutdatedMessage, ...files.map(formatFile)].join('\n') + ) + + this.files = files + } +} diff --git a/ui-admin/icons/lib/generated/check/errors/generated.ts b/ui-admin/icons/lib/generated/check/errors/generated.ts new file mode 100644 index 000000000..946ba25bf --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/generated.ts @@ -0,0 +1,12 @@ +import type { GeneratedErrorCode } from './codes.js' + +export class GeneratedError extends Error { + readonly code: GeneratedErrorCode + + constructor(code: GeneratedErrorCode, message: string) { + super(message) + + this.code = code + this.name = new.target.name + } +} diff --git a/ui-admin/icons/lib/generated/check/errors/messages.ts b/ui-admin/icons/lib/generated/check/errors/messages.ts new file mode 100644 index 000000000..a4e3f786c --- /dev/null +++ b/ui-admin/icons/lib/generated/check/errors/messages.ts @@ -0,0 +1,15 @@ +import { fileDriftStates } from '../drift/interfaces.js' + +export const commandFailedMessage = 'Command failed' + +export const directoryRequiredMessage = 'Directory is required' + +export const fileRequiredMessage = 'File is required' + +export const filesOutdatedMessage = 'Generated files are outdated' + +export const fileDriftStateMessages = { + [fileDriftStates.different]: 'content differs', + [fileDriftStates.missing]: 'missing committed file', + [fileDriftStates.unexpected]: 'unexpected committed file', +} diff --git a/ui-admin/icons/lib/generated/check/expected/format.ts b/ui-admin/icons/lib/generated/check/expected/format.ts new file mode 100644 index 000000000..4f55d65c9 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/expected/format.ts @@ -0,0 +1,41 @@ +import { readdir } from 'node:fs/promises' +import { join } from 'node:path' +import { relative } from 'node:path' +import { sep } from 'node:path' + +import { runCommand } from '../command/run.js' +import { formatCommand } from '../constants.js' +import { relativePathSeparator } from '../constants.js' +import { workspaceRootPath } from '../constants.js' +import { yarnCommand } from '../constants.js' + +const collectFiles = async (directoryPath: string, currentPath = ''): Promise> => { + const entries = await readdir(join(directoryPath, currentPath), { withFileTypes: true }) + const files = await Promise.all( + entries.map(async (entry) => { + const entryPath = currentPath ? join(currentPath, entry.name) : entry.name + + if (entry.isDirectory()) { + return collectFiles(directoryPath, entryPath) + } + + if (entry.isFile()) { + return [entryPath.split(sep).join(relativePathSeparator)] + } + + return [] + }) + ) + + return files.flat().sort((pathA, pathB) => pathA.localeCompare(pathB)) +} + +export const formatFiles = async (iconsPath: string, replacementsPath: string): Promise => { + const filePaths = [ + replacementsPath, + ...(await collectFiles(iconsPath)).map((filePath) => join(iconsPath, filePath)), + ] + const relativeFilePaths = filePaths.map((filePath) => relative(workspaceRootPath, filePath)) + + await runCommand(yarnCommand, [formatCommand, ...relativeFilePaths], { cwd: workspaceRootPath }) +} diff --git a/ui-admin/icons/lib/generated/check/expected/icons.ts b/ui-admin/icons/lib/generated/check/expected/icons.ts new file mode 100644 index 000000000..a93921d83 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/expected/icons.ts @@ -0,0 +1,26 @@ +import { runCommand } from '../command/run.js' +import { generateIconsCommand } from '../constants.js' +import { iconsGeneratorWorkspace } from '../constants.js' +import { iconsPathArgument } from '../constants.js' +import { replacementsPathArgument } from '../constants.js' +import { sourceReplacementsPath } from '../constants.js' +import { workspaceRootPath } from '../constants.js' +import { workspaceArgument } from '../constants.js' +import { yarnCommand } from '../constants.js' + +export const generateIcons = async (svgPath: string, outputPath: string): Promise => { + await runCommand( + yarnCommand, + [ + workspaceArgument, + iconsGeneratorWorkspace, + generateIconsCommand, + outputPath, + iconsPathArgument, + svgPath, + replacementsPathArgument, + sourceReplacementsPath, + ], + { cwd: workspaceRootPath } + ) +} diff --git a/ui-admin/icons/lib/generated/check/expected/replacements.ts b/ui-admin/icons/lib/generated/check/expected/replacements.ts new file mode 100644 index 000000000..d7a3a8c40 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/expected/replacements.ts @@ -0,0 +1,24 @@ +import { runCommand } from '../command/run.js' +import { generateIconsCommand } from '../constants.js' +import { generateReplacementsCommand } from '../constants.js' +import { iconsGeneratorWorkspace } from '../constants.js' +import { iconsPathArgument } from '../constants.js' +import { workspaceRootPath } from '../constants.js' +import { workspaceArgument } from '../constants.js' +import { yarnCommand } from '../constants.js' + +export const generateReplacements = async (svgPath: string, outputPath: string): Promise => { + await runCommand( + yarnCommand, + [ + workspaceArgument, + iconsGeneratorWorkspace, + generateIconsCommand, + generateReplacementsCommand, + outputPath, + iconsPathArgument, + svgPath, + ], + { cwd: workspaceRootPath } + ) +} diff --git a/ui-admin/icons/lib/generated/check/index.ts b/ui-admin/icons/lib/generated/check/index.ts new file mode 100644 index 000000000..05aa82ed2 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/index.ts @@ -0,0 +1,70 @@ +import { mkdir } from 'node:fs/promises' +import { mkdtemp } from 'node:fs/promises' +import { rm } from 'node:fs/promises' +import { join } from 'node:path' + +import { DirectoryRequiredError } from './errors/directory-required.js' +import { FileRequiredError } from './errors/file-required.js' +import { FilesOutdatedError } from './errors/files-outdated.js' +import { generatedIconsDirectoryName } from './constants.js' +import { generatedReplacementsDirectoryName } from './constants.js' +import { packageRootPath } from './constants.js' +import { replacementsFileName } from './constants.js' +import { sourceIconsPath } from './constants.js' +import { sourceReplacementsPath } from './constants.js' +import { sourceSvgPath } from './constants.js' +import { temporaryDirectoryPrefix } from './constants.js' +import { compareDirectories } from './drift/directory.js' +import { compareFiles } from './drift/file.js' +import { formatFiles } from './expected/format.js' +import { generateIcons } from './expected/icons.js' +import { generateReplacements } from './expected/replacements.js' +import { isDirectoryRequired } from './input/constraints/is-directory-required.js' +import { isFileRequired } from './input/constraints/is-file-required.js' +import { readInputPathKind } from './input/read.js' + +export const checkGenerated = async (): Promise => { + if (isDirectoryRequired(await readInputPathKind(sourceIconsPath))) { + throw new DirectoryRequiredError(sourceIconsPath) + } + + if (isDirectoryRequired(await readInputPathKind(sourceSvgPath))) { + throw new DirectoryRequiredError(sourceSvgPath) + } + + if (isFileRequired(await readInputPathKind(sourceReplacementsPath))) { + throw new FileRequiredError(sourceReplacementsPath) + } + + await mkdir(packageRootPath, { recursive: true }) + + const temporaryPath = await mkdtemp(join(packageRootPath, temporaryDirectoryPrefix)) + const generatedIconsPath = join(temporaryPath, generatedIconsDirectoryName) + const generatedReplacementsPath = join(temporaryPath, generatedReplacementsDirectoryName) + + try { + await mkdir(generatedIconsPath) + await mkdir(generatedReplacementsPath) + + await generateReplacements(sourceSvgPath, generatedReplacementsPath) + await generateIcons(sourceSvgPath, generatedIconsPath) + await formatFiles(generatedIconsPath, join(generatedReplacementsPath, replacementsFileName)) + + const outdatedFiles = [ + ...(await compareDirectories({ + actualPath: sourceIconsPath, + expectedPath: generatedIconsPath, + })), + ...(await compareFiles( + join(generatedReplacementsPath, replacementsFileName), + sourceReplacementsPath + )), + ] + + if (outdatedFiles.length > 0) { + throw new FilesOutdatedError(outdatedFiles) + } + } finally { + await rm(temporaryPath, { force: true, recursive: true }) + } +} diff --git a/ui-admin/icons/lib/generated/check/input/constraints/is-directory-required.ts b/ui-admin/icons/lib/generated/check/input/constraints/is-directory-required.ts new file mode 100644 index 000000000..35296434e --- /dev/null +++ b/ui-admin/icons/lib/generated/check/input/constraints/is-directory-required.ts @@ -0,0 +1,6 @@ +import type { InputPathKind } from '../read.js' + +import { inputPathKinds } from '../read.js' + +export const isDirectoryRequired = (kind: InputPathKind): boolean => + kind !== inputPathKinds.directory diff --git a/ui-admin/icons/lib/generated/check/input/constraints/is-file-required.ts b/ui-admin/icons/lib/generated/check/input/constraints/is-file-required.ts new file mode 100644 index 000000000..75ea79e26 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/input/constraints/is-file-required.ts @@ -0,0 +1,5 @@ +import type { InputPathKind } from '../read.js' + +import { inputPathKinds } from '../read.js' + +export const isFileRequired = (kind: InputPathKind): boolean => kind !== inputPathKinds.file diff --git a/ui-admin/icons/lib/generated/check/input/read.ts b/ui-admin/icons/lib/generated/check/input/read.ts new file mode 100644 index 000000000..993eb9c66 --- /dev/null +++ b/ui-admin/icons/lib/generated/check/input/read.ts @@ -0,0 +1,39 @@ +import { stat } from 'node:fs/promises' + +export const inputPathKinds = { + directory: 'directory', + file: 'file', + missing: 'missing', + other: 'other', + unavailable: 'unavailable', +} as const + +export type InputPathKind = (typeof inputPathKinds)[keyof typeof inputPathKinds] + +const missingInputPathErrorCode = 'ENOENT' + +const resolveFailedInputPathKind = (error: unknown): InputPathKind => { + if (error instanceof Error && 'code' in error && error.code === missingInputPathErrorCode) { + return inputPathKinds.missing + } + + return inputPathKinds.unavailable +} + +export const readInputPathKind = async (targetPath: string): Promise => { + try { + const stats = await stat(targetPath) + + if (stats.isDirectory()) { + return inputPathKinds.directory + } + + if (stats.isFile()) { + return inputPathKinds.file + } + + return inputPathKinds.other + } catch (error) { + return resolveFailedInputPathKind(error) + } +} diff --git a/ui-admin/icons/package.json b/ui-admin/icons/package.json index d1d5c2159..3d0afa6a3 100644 --- a/ui-admin/icons/package.json +++ b/ui-admin/icons/package.json @@ -9,6 +9,7 @@ ], "scripts": { "build": "yarn library build", + "check-generated": "yarn workspace @atls-ui-generators/icons node --import tsx ../../ui-admin/icons/lib/generated/check/cli.ts", "generate-icons": "yarn workspace @atls-ui-generators/icons generate-icons ../../ui-admin/icons/src/icons -i ../../ui-admin/icons/svg -r ../../ui-admin/icons/src/replacements.ts && yarn format", "generate-replacements": "yarn workspace @atls-ui-generators/icons generate-icons replacements ../../ui-admin/icons/src -i ../../ui-admin/icons/svg && yarn format", "prepack": "yarn run build", diff --git a/yarn.lock b/yarn.lock index 53fb67c63..a4d351395 100644 --- a/yarn.lock +++ b/yarn.lock @@ -328,7 +328,7 @@ __metadata: tsx: "npm:4.20.5" typescript: "npm:5.5.4" bin: - generate-icons: dist/icons.generator.js + generate-icons: dist/generator.js languageName: unknown linkType: soft