summaryrefslogtreecommitdiff
path: root/node_modules/svgo/lib/path.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/svgo/lib/path.js')
-rw-r--r--node_modules/svgo/lib/path.js141
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;