'use strict'; var json = require('@shgysk8zer0/npm-utils/json'); var yaml = require('@shgysk8zer0/npm-utils/yaml'); var fs = require('@shgysk8zer0/npm-utils/fs'); var mimes = require('@shgysk8zer0/consts/mimes'); var exts = require('@shgysk8zer0/consts/exts'); var utils = require('@shgysk8zer0/npm-utils/utils'); var consts = require('@shgysk8zer0/npm-utils/consts'); var node_path = require('node:path'); var path = require('@shgysk8zer0/npm-utils/path'); var cheerio = require('cheerio'); const CSV = ['.csv']; async function readCSVFile(path, { encoding, signal } = {}) { console.warn('CSV supported is deprecated and only offered for migrating from `svg-sprite-generator`.'); console.info(`Please run svg-use-symbols --migrate ${path} --output ${path.replace(node_path.extname(path), '.json')}`); const contents = await fs.readFile(path, { encoding, signal }); return contents .replaceAll('\r', consts.LF) .split(consts.LF) .filter(l => l.length !== 0) .map(line => line.split(',').map(c => c.trim().replaceAll('"', '') )); } const ROOT = process.cwd(); const EXT_TYPES = { json: exts.JSON, yaml: exts.YAML, csv: CSV, }; function getFileType(ext) { const match = Object.entries(EXT_TYPES).find(([, exts]) => exts.includes(ext)); if (Array.isArray(match)) { return match[0]; } } async function readConfig(path, { encoding = fs.ENCODING, signal } = {}) { const ext = node_path.extname(path); switch(getFileType(ext)) { case 'json': return json.readJSONFile(`${ROOT}/${path}`, { encoding, signal }); case 'yaml': return yaml.readYAMLFile(`${ROOT}/${path}`, { encoding, signal }); case 'csv': return readCSVFile(`${ROOT}/${path}`, { encoding, signal }) .then(Object.fromEntries); } } async function fetchIcon(url, { signal } = {}) { const resp = await fetch(url, { headers: new Headers({ Accept: mimes.SVG }), signal, }); if (! resp.ok) { throw new Error(`Error fetching ${url}`); } else if (! resp.headers.get('Content-Type').startsWith(mimes.SVG)) { throw new TypeError(`<${url}> is not an SVG. Content-Type: ${resp.headers.get('Content-Type')}`); } else { return resp.text(); } } async function loadIcon(loc, { encoding = fs.ENCODING, signal } = {}) { if (utils.isURL(loc)) { return await fetchIcon(loc, { signal }); } else { try { if (node_path.isAbsolute(loc)) { return await fs.readFile(loc, { encoding, signal }); } else { return await fs.readFile(`${ROOT}/${loc}`, { encoding, signal }); } } catch { throw new Error(`Unable to find or read file at ${loc}.`); } } } async function generateSymbol(id, loc, { encoding, signal } = {}) { const icon = await loadIcon(loc, { encoding, signal }); const svg = cheerio.load(`
${icon}
`, { xmlMode: true })('svg'); if (svg.length === 0) { throw new Error(`Missing or empty svg for ${id}`); } else { return `${svg.html()}`; } } async function writeSVG(path$1, symbols, { encoding } = {}) { if (! Array.isArray(symbols)) { throw new TypeError('symbols must be an array of s.'); } else if (typeof path$1 === 'string') { await writeSVG(path.getFileURL(path$1, ROOT), symbols, { encoding }); } else if (! (path$1 instanceof URL)) { throw new TypeError('Path must be a URL or string.'); } else { await fs.writeFile( path$1, `${symbols.join('')}`, { encoding }, ); console.info(`Wrote ${symbols.length} s to "${path$1}".`); } } async function generateSymbols(configFile, { encoding = fs.ENCODING, output, signal } = {}) { const config = await readConfig(configFile, { encoding, signal }); if (utils.isObject(config)) { if (typeof output !== 'string') { throw new Error('Missing required output option (-o or --output)'); } else { const symbols = await Promise.all( Object.entries(config).map( async ([id, loc]) => generateSymbol(id, loc, { encoding, signal }) ) ); await writeSVG(output, symbols, { encoding, signal }); } } else if (Array.isArray(config)) { if (typeof output === 'string') { throw new Error('Output is ignored when the config file contains an array for multiple output files.'); } await Promise.all(config.map(async ({ output, icons }) => { if (typeof output !== 'string') { throw new TypeError('`output` expected to be a string'); } else if (! utils.isObject(icons)) { throw new TypeError('`icons` expected to be an object of { id: path_or_url }'); } else { const symbols = await Promise.all( Object.entries(icons).map( async ([id, loc]) => generateSymbol(id, loc, { encoding, signal }) ) ); await writeSVG(output, symbols, { encoding, signal }); } })); } } async function generateSymbolsFromDirectory(directory, { encoding, output, signal } = {}) { if (typeof output !== 'string') { throw new Error('Output is a required option for directory usage.'); } const svgs = await fs.listDirByExt(`${ROOT}/${directory}`, '.svg'); const symbols = await Promise.all(svgs.map(async path => { const id = node_path.basename(path).replace(node_path.extname(path), ''); return await generateSymbol(id, path, { encoding, signal }); })); await writeSVG(output, symbols, { encoding, signal }); } exports.generateSymbol = generateSymbol; exports.generateSymbols = generateSymbols; exports.generateSymbolsFromDirectory = generateSymbolsFromDirectory; exports.writeSVG = writeSVG;