diff options
Diffstat (limited to 'node_modules/svgo/lib/path.js')
| -rw-r--r-- | node_modules/svgo/lib/path.js | 141 |
1 files changed, 86 insertions, 55 deletions
diff --git a/node_modules/svgo/lib/path.js b/node_modules/svgo/lib/path.js index 1e383dd9..814ee2e3 100644 --- a/node_modules/svgo/lib/path.js +++ b/node_modules/svgo/lib/path.js @@ -1,6 +1,6 @@ 'use strict'; -const { removeLeadingZero } = require('./svgo/tools'); +const { removeLeadingZero, toFixed } = require('./svgo/tools'); /** * @typedef {import('./types').PathDataItem} PathDataItem @@ -135,11 +135,11 @@ const readNumber = (string, cursor) => { }; /** - * @type {(string: string) => Array<PathDataItem>} + * @type {(string: string) => PathDataItem[]} */ const parsePathData = (string) => { /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = []; /** @@ -243,15 +243,20 @@ const parsePathData = (string) => { exports.parsePathData = parsePathData; /** - * @type {(number: number, precision?: number) => string} + * @type {(number: number, precision?: number) => { + * roundedStr: string, + * rounded: number + * }} */ -const stringifyNumber = (number, precision) => { +const roundAndStringify = (number, precision) => { if (precision != null) { - const ratio = 10 ** precision; - number = Math.round(number * ratio) / ratio; + number = toFixed(number, precision); } - // remove zero whole from decimal number - return removeLeadingZero(number); + + return { + roundedStr: removeLeadingZero(number), + rounded: number, + }; }; /** @@ -267,83 +272,109 @@ const stringifyNumber = (number, precision) => { */ const stringifyArgs = (command, args, precision, disableSpaceAfterFlags) => { let result = ''; - let prev = ''; - for (let i = 0; i < args.length; i += 1) { - const number = args[i]; - const numberString = stringifyNumber(number, precision); + let previous; + + for (let i = 0; i < args.length; i++) { + const { roundedStr, rounded } = roundAndStringify(args[i], precision); if ( disableSpaceAfterFlags && (command === 'A' || command === 'a') && // consider combined arcs (i % 7 === 4 || i % 7 === 5) ) { - result += numberString; - } else if (i === 0 || numberString.startsWith('-')) { + result += roundedStr; + } else if (i === 0 || rounded < 0) { // avoid space before first and negative numbers - result += numberString; - } else if (prev.includes('.') && numberString.startsWith('.')) { + result += roundedStr; + } else if ( + !Number.isInteger(previous) && + rounded != 0 && + rounded < 1 && + rounded > -1 + ) { // remove space before decimal with zero whole // only when previous number is also decimal - result += numberString; + result += roundedStr; } else { - result += ` ${numberString}`; + result += ` ${roundedStr}`; } - prev = numberString; + previous = rounded; } + return result; }; /** * @typedef {{ - * pathData: Array<PathDataItem>; + * pathData: PathDataItem[]; * precision?: number; * disableSpaceAfterFlags?: boolean; * }} StringifyPathDataOptions */ /** - * @type {(options: StringifyPathDataOptions) => string} + * @param {StringifyPathDataOptions} options + * @returns {string} */ const stringifyPathData = ({ pathData, precision, disableSpaceAfterFlags }) => { - // combine sequence of the same commands - let combined = []; - for (let i = 0; i < pathData.length; i += 1) { + if (pathData.length === 1) { + const { command, args } = pathData[0]; + return ( + command + stringifyArgs(command, args, precision, disableSpaceAfterFlags) + ); + } + + let result = ''; + let prev = { ...pathData[0] }; + + // match leading moveto with following lineto + if (pathData[1].command === 'L') { + prev.command = 'M'; + } else if (pathData[1].command === 'l') { + prev.command = 'm'; + } + + for (let i = 1; i < pathData.length; i++) { const { command, args } = pathData[i]; - if (i === 0) { - combined.push({ command, args }); - } else { - /** - * @type {PathDataItem} - */ - const last = combined[combined.length - 1]; - // match leading moveto with following lineto - if (i === 1) { - if (command === 'L') { - last.command = 'M'; - } - if (command === 'l') { - last.command = 'm'; - } + if ( + (prev.command === command && + prev.command !== 'M' && + prev.command !== 'm') || + // combine matching moveto and lineto sequences + (prev.command === 'M' && command === 'L') || + (prev.command === 'm' && command === 'l') + ) { + prev.args = [...prev.args, ...args]; + if (i === pathData.length - 1) { + result += + prev.command + + stringifyArgs( + prev.command, + prev.args, + precision, + disableSpaceAfterFlags, + ); } - if ( - (last.command === command && - last.command !== 'M' && - last.command !== 'm') || - // combine matching moveto and lineto sequences - (last.command === 'M' && command === 'L') || - (last.command === 'm' && command === 'l') - ) { - last.args = [...last.args, ...args]; + } else { + result += + prev.command + + stringifyArgs( + prev.command, + prev.args, + precision, + disableSpaceAfterFlags, + ); + + if (i === pathData.length - 1) { + result += + command + + stringifyArgs(command, args, precision, disableSpaceAfterFlags); } else { - combined.push({ command, args }); + prev = { command, args }; } } } - let result = ''; - for (const { command, args } of combined) { - result += - command + stringifyArgs(command, args, precision, disableSpaceAfterFlags); - } + return result; }; exports.stringifyPathData = stringifyPathData; |
