UNPKG

github-action-readme-generator

Version:

The docs generator for GitHub Actions. Auto-syncs action.yml to README.md with 8 sections: inputs, outputs, usage, badges, branding & more. Works as CLI or GitHub Action.

137 lines 5.91 kB
/** * This TypeScript code imports necessary modules and defines a class named 'SVGEditor' for generating SVG images. * The class has methods for initializing the SVG window, generating SVG content, and writing SVG files. * It utilizes various packages such as 'fs', 'path', '@svgdotjs/svg.js', 'feather-icons', and 'svgdom' for SVG manipulation and file operations. * The class also defines interfaces for badges and brand colors. */ import * as fs from 'node:fs'; import * as path from 'node:path'; import { registerWindow, SVG } from '@svgdotjs/svg.js'; import * as feather from 'feather-icons'; import { createSVGWindow } from 'svgdom'; /// main-module.js'; import { brandingSquareEdgeLengthInPixels, DEFAULT_BRAND_COLOR, DEFAULT_BRAND_ICON, GITHUB_ACTIONS_BRANDING_COLORS, GITHUB_ACTIONS_BRANDING_ICONS, isValidColor, isValidIcon, } from './constants.js'; import LogTask from './logtask/index.js'; /** * Utility class for generating SVG images. */ export default class SVGEditor { log; window; canvas; document; /** * Initializes a new SVGEditor instance. */ constructor() { this.log = new LogTask('SVGEditor'); } /** * Initializes the SVG window, document, and canvas if not already set up. */ initSVG() { if (!this.window) { this.window = createSVGWindow(); const { document } = this.window; registerWindow(this.window, document); if (!this.canvas) { this.canvas = SVG(document.documentElement); } } } /** * Generates a branded SVG image. * @param {string | undefined} svgPath - Path to write the generated SVG file to. * @param {Partial<FeatherIconNames>} icon - Name of the icon to use. * @param {Partial<BrandColors>} bgcolor - Background color for the image. * @returns {Promise<void>} A promise that resolves when the image is generated. */ generateSvgImage(svgPath, icon = DEFAULT_BRAND_ICON, bgcolor = DEFAULT_BRAND_COLOR) { if (!svgPath || svgPath.length === 0) { this.log.debug('No svgPath provided'); return; } if (!isValidIcon(icon)) { this.log.error(`Valid Branding Icon Names: ${GITHUB_ACTIONS_BRANDING_ICONS}`); this.log.fail(`Invalid icon name: ${icon}`); return; } if (!isValidColor(bgcolor)) { this.log.error(`Valid Branding Colors: ${GITHUB_ACTIONS_BRANDING_COLORS}`); this.log.fail('Invalid branding color'); return; } this.log.info(`SVG to generate ${icon} at ${svgPath} with color ${bgcolor}.`); // Initialize SVG this.initSVG(); // Generate SVG content const svgContent = this.generateSVGContent(icon, bgcolor); // Write SVG file this.writeSVGFile(svgPath, svgContent); this.log.debug('SVG image generated successfully'); } /** * Writes the SVG xml to disk. * @param {string} svgPath - File path to save the SVG to. * @param {string} svgContent - The XML for the SVG file. */ writeSVGFile(svgPath, svgContent) { fs.mkdirSync(path.dirname(svgPath), { recursive: true }); this.log.debug(`Writing SVG file to ${svgPath}`); fs.writeFile(svgPath, svgContent, 'utf8', () => { return this.log.debug(`SVG image generated: ${svgPath}`); }); } /** * Generates the SVG content for the branding image. * @param {FeatherIconNames} icon - Name of the icon to use. * @param {BrandColors} color - Background color for the image. * @param {number} outerViewBox - Size of the canvas for the image. * @returns {string} The generated SVG content. */ generateSVGContent(icon, color, outerViewBox = 100) { const { canvas, log } = this; // Validate canvas if (!canvas) { log.fail('Canvas not initialized'); return ''; } const svgData = feather.icons[icon]; log.debug(`SVG data to ingest: ${svgData.toSvg()}`); canvas.clear(); // Create a canvas that is `outerViewBox` x `outerViewBox` canvas .size(brandingSquareEdgeLengthInPixels, brandingSquareEdgeLengthInPixels) .viewbox(`0 0 ${outerViewBox} ${outerViewBox}`) .fill('none'); // Create a 'color' circle that touches the edges of the canvas const circleSize = outerViewBox / 2; canvas .circle('50%') .fill(color) .radius(circleSize) .cx(circleSize) .cy(circleSize) .stroke({ width: 0 }); // Create an svg box that is half the size of the parent const iconsvgOuter = canvas.nested(); iconsvgOuter.attr('overflow', 'visible').height('50%').width('50%').x('25%').y('25%'); // create a nested svg and add the feather-icon paths to the svg const iconsvg = iconsvgOuter.nested(); iconsvg.id('icon').svg(svgData.contents); // Append all of the attributes from the fether-icon for (const attr of Object.keys(svgData.attrs)) { iconsvg.attr(attr, svgData.attrs[attr]); } // invert the stroke color if it matches the background color iconsvg.stroke(color.startsWith('white') ? 'white' : 'black'); // remove the edge clipping iconsvg.attr('overflow', 'visible'); // Make the viewbox of the svg match the exact dimensions of the icon iconsvg.viewbox(iconsvg.bbox()); // Make the svg icon center itself vertically and horozonally iconsvg.height('auto').width('auto'); // return the xml file content return ['<?xml version="1.0" encoding="UTF-8" standalone="no"?>', canvas.svg(), '\n'].join('\n'); } } //# sourceMappingURL=svg-editor.mjs.map