UNPKG

@svgd/cli

Version:

Command-line utility for generating constants from SVG assets

271 lines (262 loc) 9.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { generateSvgConstants: () => generateSvgConstants, parseCliArgs: () => parseCliArgs, runCLI: () => runCLI }); module.exports = __toCommonJS(index_exports); var import_fs2 = __toESM(require("fs"), 1); var import_path2 = __toESM(require("path"), 1); // src/generate.ts var import_path = __toESM(require("path"), 1); var import_utils = require("@svgd/utils"); var import_fs = require("fs"); // src/templates.ts var jsRowTemplate = ({ name, d, quote }) => `export const ${name} = ${quote}${d}${quote}; `; var jsRowTemplateWithJSDoc = ({ name, d, image, quote, filePath, ts }) => `/** * @filepath ${filePath} * @return ${image} */ export const ${name} = ${quote}${d}${quote}${ts ? ` as "${name}"` : ""}; `; var dtsRowTemplate = ({ name, image, filePath }) => `/** * @filepath ${filePath} * @return ${image} */ export const ${name}: string; `; var mdRowTemplate = ({ name, filePath, relativePath }) => `| ![](${relativePath}) | ${name} | ${filePath} |`; var mdFileTemplate = (rows) => `# List of icons | Source | Name | Path | |---|---|---| ${rows} `; var htmlRowTemplate = ({ name, filePath, svg }) => `<tr><td>${svg}</td><td>${name}</td><td>${filePath}</td></tr>`; var htmlFileTemplate = (rows) => `<!DOCTYPE html> <html lang=""> <head> <style> table { border-collapse: collapse; } th { text-align: center; border: 1px solid darkgray; padding: 4px 8px; } td { text-align: left; border: 1px solid darkgray; padding: 4px 8px; } </style> </head> <body> <table> <tr><th>Icon</th><th>Name</th><th>Path</th></tr> ${rows} </table> </body> </html> `; // src/generate.ts var defoultOptions = { input: "src/assets/icons", output: "src/components/Icon/paths.js", quote: false, template: "", format: "camelCase", colors: false, size: 24 }; async function generateSvgConstants(options) { const root = process.cwd(); const filledOptions = { ...defoultOptions, ...options }; const baseDir = import_path.default.resolve(root, filledOptions.input); const svgoConfig = (0, import_utils.getSvgoConfig)({ ...import_utils.defaultConfig, colors: filledOptions.colors, resize: { targetViewBox: { minX: 0, minY: 0, width: filledOptions.size ?? 24, height: filledOptions.size ?? 24 } } }); const svgFiles = (0, import_utils.getSvgFileNames)(baseDir); const singleQuote = filledOptions.quote; const quote = singleQuote ? "'" : '"'; const outputs = /* @__PURE__ */ new Map(); let md; if (filledOptions.md) { md = { rows: [], fileTemplate: mdFileTemplate, rowTemplate: mdRowTemplate, path: import_path.default.resolve(root, filledOptions.md) }; outputs.set(md.path, md); } let html; if (filledOptions.html) { html = { rows: [], fileTemplate: htmlFileTemplate, rowTemplate: htmlRowTemplate, path: import_path.default.resolve(root, filledOptions.html) }; outputs.set(html.path, html); } await Promise.all(svgFiles.map(async (file, index) => { try { const getRelativePath = getRelativePathFactory(file); const constantName = (0, import_utils.generateConstantName)( file, baseDir, filledOptions.template, filledOptions.format ); const outputFileName = (0, import_utils.generateFileName)(file, baseDir, filledOptions.output); const outputFilePath = import_path.default.resolve(root, outputFileName); let constants = outputs.get(outputFilePath); if (!constants) { constants = { rows: [], path: outputFilePath, rowTemplate: filledOptions.dts ? jsRowTemplate : jsRowTemplateWithJSDoc }; outputs.set(outputFilePath, constants); } let dts; if (filledOptions.dts) { const dtsOutputFilePath = outputFilePath.replace(/\.js|\.ts$/, ".d.ts"); dts = outputs.get(dtsOutputFilePath); if (!dts) { dts = { rows: [], path: dtsOutputFilePath, rowTemplate: dtsRowTemplate }; outputs.set(dtsOutputFilePath, dts); } } const d = (0, import_utils.parseSvg)((0, import_fs.readFileSync)(file, "utf8"), svgoConfig); const svg = (0, import_utils.getSvg)(d); const png = await (0, import_utils.getPng)(svg); const templateProps = { name: constantName, d, quote, svg, image: `![](data:image/png;base64,${png})`, filePath: import_path.default.relative(baseDir, file).split("\\").join("/"), ts: /\.ts$/.test(outputFilePath) }; const orderedRowItem = (code) => ({ order: constantName, code }); constants.rows.push(orderedRowItem(constants.rowTemplate({ ...templateProps, relativePath: getRelativePath(outputFilePath) }))); dts?.rows.push(orderedRowItem(dts.rowTemplate({ ...templateProps, relativePath: getRelativePath(dts.path) }))); md?.rows.push(orderedRowItem(md.rowTemplate({ ...templateProps, relativePath: getRelativePath(md.path) }))); html?.rows.push(orderedRowItem(html.rowTemplate({ ...templateProps, relativePath: getRelativePath(html.path) }))); } catch (error) { console.error(`Error processing svg file ${file}:`, error); } if ((index + 1) % 100 === 0) { console.log(`Processed svg files: ${index + 1}/${svgFiles.length}`); } })); return [...outputs.entries()].map(([outPath, rawData]) => { const content = rawData.rows.sort(({ order: a }, { order: b }) => a.localeCompare(b)).map(({ code }) => code).join("\n"); return { path: outPath, content: rawData.fileTemplate ? rawData.fileTemplate(content) : content }; }); } var getRelativePathFactory = (file) => (absolutePath) => import_path.default.relative(import_path.default.dirname(absolutePath), file).split("\\").join("/"); // src/parseCliArgs.ts var import_commander = require("commander"); function commanderParseInt(value) { const parsedValue = parseInt(value, 10); if (isNaN(parsedValue)) { throw new import_commander.InvalidArgumentError("Not a number."); } return parsedValue; } function parseCliArgs(argv) { const program = (0, import_commander.createCommand)(); program.version("1.0.5").description("CLI tool to generate constants from SVG files").option("-i, --input <directory>", "Input directory containing SVG files", "src/assets/icons").option("-o, --output <file>", "Output file path or pattern", "src/components/Icon/paths.js").option("-c, --colors", "Keep colors", false).option("-s, --size <number>", "Icon Size", commanderParseInt, 24).option("-q, --quote", "Use single quotes in the output", false).option("-t, --template <string>", "Template string for naming convention", "").option("-m, --md <string>", "Path to the output MD file", "").option("-h, --html <string>", "Path to the output HTML file", "").option("-d, --dts", "Path to the output HTML file", false).option( "-f, --format <format>", "Naming format: camelCase, PascalCase, snake_case, SCREAMING_SNAKE_CASE, or material", "camelCase" ).parse(argv); return program.opts(); } // src/index.ts async function runCLI(argv) { const options = parseCliArgs(argv); const generatedFiles = await generateSvgConstants(options); generatedFiles.forEach(({ path: outputFilePath, content }) => { ensureDirectoryExistence(outputFilePath); import_fs2.default.writeFileSync(outputFilePath, content, "utf8"); console.log(`Constants file successfully created: ${outputFilePath}`); }); } function ensureDirectoryExistence(filePath) { const dirname = import_path2.default.dirname(filePath); if (!import_fs2.default.existsSync(dirname)) { import_fs2.default.mkdirSync(dirname, { recursive: true }); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { generateSvgConstants, parseCliArgs, runCLI });