fantasticon
Version:
Icon font generation tool
298 lines (289 loc) • 9.11 kB
JavaScript
import {
DEFAULT_OPTIONS,
FontAssetType,
OtherAssetType,
__commonJS,
__require,
checkPath,
generateFonts,
readFile,
removeUndefined
} from "../chunk-I73JJ2KG.js";
// package.json
var require_package = __commonJS({
"package.json"(exports, module) {
module.exports = {
name: "fantasticon",
version: "0.0.0",
description: "Icon font generation tool",
repository: {
type: "git",
url: "git+https://github.com/tancredi/fantasticon.git"
},
keywords: [
"icons",
"fonts",
"iconfonts",
"svg",
"vector"
],
author: "Tancredi Trugenberger",
bugs: {
url: "https://github.com/tancredi/fantasticon/issues"
},
homepage: "https://github.com/tancredi/fantasticon#readme",
type: "module",
exports: {
require: "./dist/index.cjs",
import: "./dist/index.js"
},
main: "dist/index.cjs",
module: "dist/index.js",
types: "dist/index.d.ts",
bin: {
fantasticon: "bin/fantasticon"
},
license: "MIT",
scripts: {
test: "vitest run",
"test:watch": "vitest dev",
build: "rimraf dist && npm run ts",
ts: "tsup --dts --format esm,cjs src/index.ts src/cli/index.ts",
"build:package:cjs": `touch ./dist/cjs/package.json && echo '{"type": "commonjs"}' > ./dist/cjs/package.json`,
"build:cjs": "tsc --project ./tsconfig.cjs.json && npm run build:package:cjs",
"build:package:esm": `touch ./dist/esm/package.json && echo '{"type": "module"}' > ./dist/esm/package.json`,
"build:esm": "tsc --project ./tsconfig.json && npm run build:package:esm",
watch: "npm run ts -- --watch",
typecheck: "tsc --noEmit --project tsconfig.test.json --noEmit",
lint: "prettier --check .",
fix: "prettier --write ."
},
files: [
"bin/fantasticon",
"dist/**/*",
"!dist/**/{__mocks__,__tests__}/",
"templates/*.hbs"
],
prepublish: "build",
dependencies: {
case: "^1.6.3",
"cli-color": "^2.0.4",
commander: "^14.0.2",
glob: "^13.0.0",
handlebars: "^4.7.8",
slugify: "^1.6.6",
svg2ttf: "^6.0.3",
svgicons2svgfont: "^15.0.1",
ttf2eot: "^3.1.0",
ttf2woff: "^3.0.0",
ttf2woff2: "^8.0.0"
},
devDependencies: {
"@types/cli-color": "^2.0.6",
"@types/glob": "^9.0.0",
"@types/node": "^25.0.3",
"@types/svg2ttf": "^5.0.3",
"@types/svgicons2svgfont": "^14.0.0",
"@types/ttf2eot": "^2.0.2",
"@types/ttf2woff": "^2.0.4",
"@types/ttf2woff2": "^6.0.0",
prettier: "^3.7.4",
rimraf: "^6.1.2",
"semantic-release": "^25.0.2",
tsup: "^8.5.1",
typescript: "^5.9.3",
vitest: "^4.0.16"
},
jest: {
preset: "ts-jest",
testEnvironment: "node",
rootDir: "./src",
transform: {
"^.+\\.tsx?$": [
"ts-jest",
{
tsconfig: "./tsconfig.test.json"
}
]
}
},
engines: {
node: ">= 22.0"
}
};
}
});
// src/cli/index.ts
import * as commander from "commander";
// src/cli/config-loader.ts
import { join } from "path";
var DEFAULT_FILEPATHS = [
".fantasticonrc",
"fantasticonrc",
".fantasticonrc.json",
"fantasticonrc.json",
".fantasticonrc.js",
"fantasticonrc.js"
];
var attemptLoading = async (filepath) => {
if (await checkPath(filepath, "file")) {
try {
return __require(join(process.cwd(), filepath));
} catch (err) {
}
try {
return JSON.parse(await readFile(filepath, "utf8"));
} catch (err) {
}
throw new Error(`Failed parsing configuration at '${filepath}'`);
}
};
var loadConfig = async (filepath) => {
let loadedConfigPath = null;
let loadedConfig = {};
if (filepath) {
loadedConfig = await attemptLoading(filepath);
loadedConfigPath = filepath;
} else {
for (const path of DEFAULT_FILEPATHS) {
loadedConfig = await attemptLoading(path);
if (loadedConfig) {
loadedConfigPath = path;
break;
}
}
}
return { loadedConfig, loadedConfigPath };
};
// src/cli/logger.ts
import color from "cli-color";
// src/utils/string.ts
var pluralize = (word, amount) => amount === 1 ? word : `${word}s`;
// src/cli/logger.ts
var getLogger = (debug = false, silent = false) => ({
error(error) {
const message = error instanceof Error && error.message || error;
console.log(color.red(message));
debug && error instanceof Error && console.log(error.stack);
},
log(...values) {
!silent && console.log(...values);
},
start(loadedConfigPath = null) {
this.log(color.yellow(`Generating font kit...`));
if (loadedConfigPath) {
this.log(
color.green(
`\u2714 Using configuration file: ${color.green.bold(loadedConfigPath)}`
)
);
}
},
results({ assetsIn, writeResults, options: { inputDir } }) {
const iconsCount = Object.values(assetsIn).length;
this.log(
color.white(
`\u2714 ${iconsCount} ${pluralize("SVG", iconsCount)} found in ${inputDir}`
)
);
for (const { writePath } of writeResults) {
this.log(color.blue(`\u2714 Generated`, color.blueBright(writePath)));
}
this.log(color.green.bold("Done"));
}
});
// src/utils/module.ts
var getPackageInfo = () => {
const { bin, name, version } = require_package();
return { bin, name, version };
};
// src/cli/index.ts
var packageInfo = getPackageInfo();
var getCommandName = () => packageInfo.bin && Object.keys(packageInfo.bin)[0] || packageInfo.name;
var cli = async () => {
config();
const input = commander.program.parse(process.argv);
const { debug, silent, config: configPath } = input.opts();
const logger = getLogger(debug, silent);
try {
const { loadedConfig, loadedConfigPath } = await loadConfig(configPath);
const results = await run(await buildOptions(input, loadedConfig));
logger.start(loadedConfigPath);
logger.results(results);
} catch (error) {
logger.error(error);
process.exitCode = 1;
}
};
var printList = (available, defaults) => ` (default: ${defaults.join(", ")}, available: ${Object.values(
available
).join(", ")})`;
var printDefaultValue = (value) => {
let printVal = String(value);
if (typeof value === "undefined") {
return "";
}
return ` (default: ${printVal})`;
};
var printDefaultOption = (key) => printDefaultValue(DEFAULT_OPTIONS[key]);
var printConfigPaths = () => DEFAULT_FILEPATHS.join(" | ");
var config = () => {
commander.program.storeOptionsAsProperties(false).name(getCommandName()).version(packageInfo.version).arguments("[input-dir]").option(
"-c, --config <value>",
`custom config path (default: ${printConfigPaths()})`
).option("-o, --output <value>", "specify output directory").option(
"-n, --name <value>",
"base name of the font set used both as default asset name" + printDefaultOption("name")
).option(
"-t, --font-types <value...>",
`specify font formats to generate` + printList(FontAssetType, DEFAULT_OPTIONS.fontTypes)
).option(
"-g --asset-types <value...>",
`specify other asset types to generate` + printList(OtherAssetType, DEFAULT_OPTIONS.assetTypes)
).option(
"-h, --font-height <value>",
"the output font height (icons will be scaled so the highest has this height)" + printDefaultOption("fontHeight")
).option(
"--descent <value>",
"the font descent" + printDefaultOption("descent")
).option(
"--normalize [bool]",
"normalize icons by scaling them to the height of the highest icon" + printDefaultOption("normalize")
).option("-r, --round [bool]", "setup the SVG path rounding [10e12]").option(
"--selector <value>",
"use a CSS selector instead of 'tag + prefix'" + printDefaultOption("selector")
).option(
"-p, --prefix <value>",
"CSS class prefix" + printDefaultOption("prefix")
).option(
"--tag <value>",
"CSS base tag for icons" + printDefaultOption("tag")
).option(
"-u, --fonts-url <value>",
"public URL to the fonts directory (used in the generated CSS)"
).option("--debug", "display errors stack trace" + printDefaultValue(false)).option("--silent", "run with no logs" + printDefaultValue(false));
};
var buildOptions = async (cmd, loadedConfig = {}) => {
const [inputDir] = cmd.args;
const opts = cmd.opts();
return {
...loadedConfig,
...removeUndefined({
inputDir,
outputDir: opts.output,
name: opts.name,
fontTypes: opts.fontTypes,
assetTypes: opts.assetTypes,
fontHeight: opts.fontHeight,
descent: opts.descent,
normalize: opts.normalize,
round: opts.round,
selector: opts.selector,
tag: opts.tag,
prefix: opts.prefix,
fontsUrl: opts.fontsUrl
})
};
};
var run = async (options) => await generateFonts(options, true);
cli();