UNPKG

@amandaghassaei/flat-svg

Version:

A TypeScript library for converting nested SVGs into a flat list of elements, paths, or segments and applying style-based filters.

86 lines (82 loc) 3.57 kB
import { isArray, isNumber, isPositiveNumber, isString } from '@amandaghassaei/type-checks'; import { SVGParserElementNode, SVGElementProperties } from './types-public'; /** * Strip leading and trailing whitespace from a string (equivalent to `.trim()`). * @param string Input string. * @returns The input with all leading/trailing whitespace removed. */ export function removeWhitespacePadding(string: string) { return string.replace(/^\s+|\s+$/g,''); } /** * Wrap a string of inner element markup with an `<svg ...>` open tag carrying * the given root's attributes and a matching close tag. Used by FlatSVG's * `*AsSVG` getters to round-trip flattened output as a complete document. * @param root svg-parser root node whose attributes populate the wrapper. * @param svgElements Inner element markup to splice between the tags. * @returns A complete `<svg ...>...</svg>` document string. */ export function wrapWithSVGTag(root: SVGParserElementNode, svgElements: string) { /* c8 ignore start -- defensive: svg-parser always emits a `properties` object (empty `{}` for elements with no attributes), so the `|| {}` fallback only fires if the library changes its contract. Verified for v3.x. */ const properties = root.properties || {}; /* c8 ignore stop */ return `<svg ${Object.keys(properties) .map((key) => `${key}="${properties[key as keyof SVGElementProperties]}"`) .join(' ')}>\n${svgElements}\n</svg>`; } /** * Serialize a properties object to a space-separated `key="value"` attribute * string for embedding inside an SVG tag. Every own enumerable key is emitted. * @param properties Object of SVG attribute key/value pairs. * @returns Attribute string (trailing space included). */ export function propertiesToAttributesString(properties: object) { const keys = Object.keys(properties); let attrs = ''; for (let i = 0, length = keys.length; i < length; i++) { const key = keys[i]; attrs += `${key}="${(properties as Record<string, unknown>)[key]}" `; } return attrs; } /** * Normalize a `stroke-dasharray` value (string, number, array, or undefined) * into a positive-number array, doubling odd-length lists per the SVG spec. * @param value Raw dasharray value from an SVG attribute or caller input. * @returns Even-length array of positive numbers (empty for undefined/`''`). */ export function convertToDashArray(value: string | number | number[] | undefined) { let dashArray: number[] = []; if (value === '' || value === undefined) return dashArray; if (isNumber(value)) { if (!isPositiveNumber(value)) { throw new Error(`Expected positive number for stroke-dasharray value, got ${value}.`); } dashArray = [value as number]; } else if (isString(value)) { dashArray = (value as string).split(' ').map(_el => { const el = Number.parseFloat(_el); if (!isPositiveNumber(el)) { throw new Error(`Expected positive number for stroke-dasharray value, got ${el} from string "${_el}".`); } return el; }); } else if (isArray(value)) { for (let i = 0, len = (value as number[]).length; i < len; i++) { const el = (value as number[])[i]; if (!isPositiveNumber(el)) { throw new Error(`Expected positive number for stroke-dasharray value, got ${el} from array ${JSON.stringify(value)}.`); } dashArray.push(el); } } else { throw new Error(`Invalid type ${typeof value} for stroke-dasharray property ${value}.`); } if (dashArray.length % 2 === 1) { // Odd length dash arrays should be repeated. dashArray = [...dashArray, ...dashArray]; } return dashArray; }