svg-pathdata
Advanced tools
Comparing version 5.0.0 to 5.0.1
@@ -0,1 +1,6 @@ | ||
<a name="5.0.1"></a> | ||
## [5.0.1](https://github.com/nfroidure/svg-pathdata/compare/v5.0.0...v5.0.1) (2018-06-03) | ||
<a name="5.0.0"></a> | ||
@@ -2,0 +7,0 @@ # [5.0.0](https://github.com/nfroidure/svg-pathdata/compare/v4.0.0...v5.0.0) (2018-06-02) |
import { SVGCommand, TransformFunction } from "./SVGPathData"; | ||
import { TransformableSVG } from "./TransformableSVG"; | ||
export declare class SVGPathDataParser extends TransformableSVG { | ||
curCommand: any; | ||
state: number; | ||
curNumber: string; | ||
private curNumber; | ||
private curCommandType; | ||
private curCommandRelative; | ||
private canParseCommandOrComma; | ||
private curNumberHasExp; | ||
private curNumberHasExpDigits; | ||
private curNumberHasDecimal; | ||
private curArgs; | ||
constructor(); | ||
@@ -14,26 +19,2 @@ finish(commands?: SVGCommand[]): SVGCommand[]; | ||
transform(transform: TransformFunction): this; | ||
static readonly STATE_WSP: number; | ||
static readonly STATE_WSPS: number; | ||
static readonly STATE_COMMA: number; | ||
static readonly STATE_COMMAS: number; | ||
static readonly STATE_COMMAS_WSPS: number; | ||
static readonly STATE_NUMBER: number; | ||
static readonly STATE_NUMBER_DIGITS: number; | ||
static readonly STATE_NUMBER_INT: number; | ||
static readonly STATE_NUMBER_FLOAT: number; | ||
static readonly STATE_NUMBER_EXP: number; | ||
static readonly STATE_NUMBER_EXPSIGN: number; | ||
static readonly STATE_NUMBER_MASK: number; | ||
static readonly STATE_RELATIVE: number; | ||
static readonly STATE_CLOSE_PATH: number; | ||
static readonly STATE_MOVE_TO: number; | ||
static readonly STATE_LINE_TO: number; | ||
static readonly STATE_HORIZ_LINE_TO: number; | ||
static readonly STATE_VERT_LINE_TO: number; | ||
static readonly STATE_CURVE_TO: number; | ||
static readonly STATE_SMOOTH_CURVE_TO: number; | ||
static readonly STATE_QUAD_TO: number; | ||
static readonly STATE_SMOOTH_QUAD_TO: number; | ||
static readonly STATE_ARC: number; | ||
static readonly STATE_COMMANDS_MASK: number; | ||
} |
"use strict"; | ||
// Parse SVG PathData | ||
// http://www.w3.org/TR/SVG/paths.html#PathDataBNF | ||
var __extends = (this && this.__extends) || (function () { | ||
@@ -15,34 +13,26 @@ var extendStatics = Object.setPrototypeOf || | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var _a; | ||
// Parse SVG PathData | ||
// http://www.w3.org/TR/SVG/paths.html#PathDataBNF | ||
var SVGPathData_1 = require("./SVGPathData"); | ||
var TransformableSVG_1 = require("./TransformableSVG"); | ||
// Private consts : Char groups | ||
var WSP = [" ", "\t", "\r", "\n"]; | ||
var DIGITS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; | ||
var SIGNS = ["-", "+"]; | ||
var EXPONENTS = ["e", "E"]; | ||
var DECPOINT = ["."]; | ||
var FLAGS = ["0", "1"]; | ||
var COMMA = [","]; | ||
var COMMANDS = [ | ||
"m", | ||
"M", | ||
"z", | ||
"Z", | ||
"l", | ||
"L", | ||
"h", | ||
"H", | ||
"v", | ||
"V", | ||
"c", | ||
"C", | ||
"s", | ||
"S", | ||
"q", | ||
"Q", | ||
"t", | ||
"T", | ||
"a", | ||
"A", | ||
]; | ||
var isWhiteSpace = function (c) { return " " === c || "\t" === c || "\r" === c || "\n" === c; }; | ||
var isDigit = function (c) { | ||
return "0".charCodeAt(0) <= c.charCodeAt(0) && c.charCodeAt(0) <= "9".charCodeAt(0); | ||
}; | ||
var COMMANDS = "mMzZlLhHvVcCsSqQtTaA"; | ||
// @ts-ignore | ||
var COMMAND_ARG_COUNTS = (_a = {}, | ||
_a[SVGPathData_1.SVGPathData.MOVE_TO] = 2, | ||
_a[SVGPathData_1.SVGPathData.LINE_TO] = 2, | ||
_a[SVGPathData_1.SVGPathData.HORIZ_LINE_TO] = 1, | ||
_a[SVGPathData_1.SVGPathData.VERT_LINE_TO] = 1, | ||
_a[SVGPathData_1.SVGPathData.CLOSE_PATH] = 0, | ||
_a[SVGPathData_1.SVGPathData.QUAD_TO] = 4, | ||
_a[SVGPathData_1.SVGPathData.SMOOTH_QUAD_TO] = 2, | ||
_a[SVGPathData_1.SVGPathData.CURVE_TO] = 6, | ||
_a[SVGPathData_1.SVGPathData.SMOOTH_CURVE_TO] = 4, | ||
_a[SVGPathData_1.SVGPathData.ARC] = 7, | ||
_a); | ||
var SVGPathDataParser = /** @class */ (function (_super) { | ||
@@ -52,5 +42,10 @@ __extends(SVGPathDataParser, _super); | ||
var _this = _super.call(this) || this; | ||
_this.curCommand = undefined; | ||
_this.state = SVGPathDataParser.STATE_COMMAS_WSPS; | ||
_this.curNumber = ""; | ||
_this.curCommandType = -1; | ||
_this.curCommandRelative = false; | ||
_this.canParseCommandOrComma = true; | ||
_this.curNumberHasExp = false; | ||
_this.curNumberHasExpDigits = false; | ||
_this.curNumberHasDecimal = false; | ||
_this.curArgs = []; | ||
return _this; | ||
@@ -60,458 +55,221 @@ } | ||
if (commands === void 0) { commands = []; } | ||
var result = this.parse(" ", commands); | ||
this.parse(" ", commands); | ||
// Adding residual command | ||
if (undefined !== this.curCommand) { | ||
if (this.curCommand.invalid) { | ||
throw new SyntaxError("Unterminated command at the path end."); | ||
} | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK; | ||
if (0 !== this.curArgs.length || !this.canParseCommandOrComma) { | ||
throw new SyntaxError("Unterminated command at the path end."); | ||
} | ||
return result; | ||
return commands; | ||
}; | ||
SVGPathDataParser.prototype.parse = function (str, commands) { | ||
var _this = this; | ||
if (commands === void 0) { commands = []; } | ||
var finishCommand = function (command) { | ||
commands.push(command); | ||
_this.curArgs.length = 0; | ||
_this.canParseCommandOrComma = true; | ||
}; | ||
for (var i = 0; i < str.length; i++) { | ||
var c = str[i]; | ||
// White spaces parsing | ||
if (this.state & SVGPathDataParser.STATE_WSP || | ||
this.state & SVGPathDataParser.STATE_WSPS) { | ||
if (-1 !== WSP.indexOf(str[i])) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_WSP; | ||
// any space stops current number parsing | ||
if ("" !== this.curNumber) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
else { | ||
continue; | ||
} | ||
} | ||
if (isDigit(c)) { | ||
this.curNumber += c; | ||
this.curNumberHasExpDigits = this.curNumberHasExp; | ||
continue; | ||
} | ||
// Commas parsing | ||
if (this.state & SVGPathDataParser.STATE_COMMA || | ||
this.state & SVGPathDataParser.STATE_COMMAS) { | ||
if (-1 !== COMMA.indexOf(str[i])) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMA; | ||
// any comma stops current number parsing | ||
if ("" !== this.curNumber) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
else { | ||
continue; | ||
} | ||
} | ||
if ("e" === c || "E" === c) { | ||
this.curNumber += c; | ||
this.curNumberHasExp = true; | ||
continue; | ||
} | ||
// Numbers parsing : -125.25e-125 | ||
if (this.state & SVGPathDataParser.STATE_NUMBER) { | ||
// Reading the sign | ||
if ((this.state & SVGPathDataParser.STATE_NUMBER_MASK) === | ||
SVGPathDataParser.STATE_NUMBER) { | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_INT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
if (-1 !== SIGNS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
continue; | ||
} | ||
if (("-" === c || "+" === c) && this.curNumberHasExp && !this.curNumberHasExpDigits) { | ||
this.curNumber += c; | ||
continue; | ||
} | ||
// if we already have a ".", it means we are starting a new number | ||
if ("." === c && !this.curNumberHasExp && !this.curNumberHasDecimal) { | ||
this.curNumber += c; | ||
this.curNumberHasDecimal = true; | ||
continue; | ||
} | ||
// New number | ||
if (this.curNumber && -1 !== this.curCommandType) { | ||
var val = Number(this.curNumber); | ||
if (isNaN(val)) { | ||
throw new SyntaxError("Invalid number ending at " + i); | ||
} | ||
// Reading the exponent sign | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_EXPSIGN) { | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_EXPSIGN; | ||
this.state |= SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
if (-1 !== SIGNS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
continue; | ||
if (this.curCommandType === SVGPathData_1.SVGPathData.ARC) { | ||
if (0 === this.curArgs.length || 1 === this.curArgs.length) { | ||
if (0 > val) { | ||
throw new SyntaxError("Expected positive number, got \"" + val + "\" at index \"" + i + "\""); | ||
} | ||
} | ||
} | ||
// Reading digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_DIGITS) { | ||
if (-1 !== DIGITS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
continue; | ||
else if (3 === this.curArgs.length || 4 === this.curArgs.length) { | ||
if ("0" !== this.curNumber && "1" !== this.curNumber) { | ||
throw new SyntaxError("Expected a flag, got \"" + this.curNumber + "\" at index \"" + i + "\""); | ||
} | ||
} | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
} | ||
// Ended reading left side digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_INT) { | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_INT; | ||
// if got a point, reading right side digits | ||
if (-1 !== DECPOINT.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_FLOAT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
continue; | ||
// if got e/E, reading the exponent | ||
} | ||
else if (-1 !== EXPONENTS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_EXP | | ||
SVGPathDataParser.STATE_NUMBER_EXPSIGN; | ||
continue; | ||
} | ||
// else we"re done with that number | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
// Ended reading decimal digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_FLOAT) { | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_FLOAT; | ||
// if got e/E, reading the exponent | ||
if (-1 !== EXPONENTS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_EXP | | ||
SVGPathDataParser.STATE_NUMBER_EXPSIGN; | ||
continue; | ||
} | ||
// else we"re done with that number | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
// Ended reading exponent digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_EXP) { | ||
// we"re done with that number | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
} | ||
// New number | ||
if (this.curNumber) { | ||
// Horizontal move to command (x) | ||
if (this.state & SVGPathDataParser.STATE_HORIZ_LINE_TO) { | ||
if (undefined === this.curCommand) { | ||
commands.push({ | ||
this.curArgs.push(val); | ||
if (this.curArgs.length === COMMAND_ARG_COUNTS[this.curCommandType]) { | ||
if (SVGPathData_1.SVGPathData.HORIZ_LINE_TO === this.curCommandType) { | ||
finishCommand({ | ||
type: SVGPathData_1.SVGPathData.HORIZ_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
x: Number(this.curNumber), | ||
relative: this.curCommandRelative, | ||
x: val, | ||
}); | ||
} | ||
else { | ||
this.curCommand.x = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Vertical move to command (y) | ||
} | ||
else if (this.state & SVGPathDataParser.STATE_VERT_LINE_TO) { | ||
if (undefined === this.curCommand) { | ||
commands.push({ | ||
else if (SVGPathData_1.SVGPathData.VERT_LINE_TO === this.curCommandType) { | ||
finishCommand({ | ||
type: SVGPathData_1.SVGPathData.VERT_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
y: Number(this.curNumber), | ||
relative: this.curCommandRelative, | ||
y: val, | ||
}); | ||
// Move to / line to / smooth quadratic curve to commands (x, y) | ||
} | ||
else { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Move to / line to / smooth quadratic curve to commands (x, y) | ||
} | ||
else if (this.state & SVGPathDataParser.STATE_MOVE_TO || | ||
this.state & SVGPathDataParser.STATE_LINE_TO || | ||
this.state & SVGPathDataParser.STATE_SMOOTH_QUAD_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
type: this.state & SVGPathDataParser.STATE_MOVE_TO | ||
? SVGPathData_1.SVGPathData.MOVE_TO | ||
: this.state & SVGPathDataParser.STATE_LINE_TO | ||
? SVGPathData_1.SVGPathData.LINE_TO | ||
: SVGPathData_1.SVGPathData.SMOOTH_QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
x: Number(this.curNumber), | ||
}; | ||
} | ||
else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} | ||
else { | ||
delete this.curCommand.invalid; | ||
this.curCommand.y = Number(this.curNumber); | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
else if (this.curCommandType === SVGPathData_1.SVGPathData.MOVE_TO || | ||
this.curCommandType === SVGPathData_1.SVGPathData.LINE_TO || | ||
this.curCommandType === SVGPathData_1.SVGPathData.SMOOTH_QUAD_TO) { | ||
finishCommand({ | ||
type: this.curCommandType, | ||
relative: this.curCommandRelative, | ||
x: this.curArgs[0], | ||
y: this.curArgs[1], | ||
}); | ||
// Switch to line to state | ||
if (this.state & SVGPathDataParser.STATE_MOVE_TO) { | ||
this.state ^= SVGPathDataParser.STATE_MOVE_TO; | ||
this.state |= SVGPathDataParser.STATE_LINE_TO; | ||
if (SVGPathData_1.SVGPathData.MOVE_TO === this.curCommandType) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.LINE_TO; | ||
} | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Curve to commands (x1, y1, x2, y2, x, y) | ||
} | ||
else if (this.state & SVGPathDataParser.STATE_CURVE_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
else if (this.curCommandType === SVGPathData_1.SVGPathData.CURVE_TO) { | ||
finishCommand({ | ||
type: SVGPathData_1.SVGPathData.CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
x1: Number(this.curNumber), | ||
}; | ||
relative: this.curCommandRelative, | ||
x1: this.curArgs[0], | ||
y1: this.curArgs[1], | ||
x2: this.curArgs[2], | ||
y2: this.curArgs[3], | ||
x: this.curArgs[4], | ||
y: this.curArgs[5], | ||
}); | ||
} | ||
else if (undefined === this.curCommand.x1) { | ||
this.curCommand.x1 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y1) { | ||
this.curCommand.y1 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.x2) { | ||
this.curCommand.x2 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y2) { | ||
this.curCommand.y2 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Smooth curve to commands (x1, y1, x, y) | ||
} | ||
else if (this.state & SVGPathDataParser.STATE_SMOOTH_CURVE_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
else if (this.curCommandType === SVGPathData_1.SVGPathData.SMOOTH_CURVE_TO) { | ||
finishCommand({ | ||
type: SVGPathData_1.SVGPathData.SMOOTH_CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
x2: Number(this.curNumber), | ||
}; | ||
relative: this.curCommandRelative, | ||
x2: this.curArgs[0], | ||
y2: this.curArgs[1], | ||
x: this.curArgs[2], | ||
y: this.curArgs[3], | ||
}); | ||
} | ||
else if (undefined === this.curCommand.x2) { | ||
this.curCommand.x2 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y2) { | ||
this.curCommand.y2 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Quadratic bezier curve to commands (x1, y1, x, y) | ||
} | ||
else if (this.state & SVGPathDataParser.STATE_QUAD_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
else if (this.curCommandType === SVGPathData_1.SVGPathData.QUAD_TO) { | ||
finishCommand({ | ||
type: SVGPathData_1.SVGPathData.QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
x1: Number(this.curNumber), | ||
}; | ||
relative: this.curCommandRelative, | ||
x1: this.curArgs[0], | ||
y1: this.curArgs[1], | ||
x: this.curArgs[2], | ||
y: this.curArgs[3], | ||
}); | ||
} | ||
else if (undefined === this.curCommand.x1) { | ||
this.curCommand.x1 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y1) { | ||
this.curCommand.y1 = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Elliptic arc commands (rX, rY, xRot, lArcFlag, sweepFlag, x, y) | ||
} | ||
else if (this.state & SVGPathDataParser.STATE_ARC) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
else if (this.curCommandType === SVGPathData_1.SVGPathData.ARC) { | ||
finishCommand({ | ||
type: SVGPathData_1.SVGPathData.ARC, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
rX: Number(this.curNumber), | ||
}; | ||
relative: this.curCommandRelative, | ||
rX: this.curArgs[0], | ||
rY: this.curArgs[1], | ||
xRot: this.curArgs[2], | ||
lArcFlag: this.curArgs[3], | ||
sweepFlag: this.curArgs[4], | ||
x: this.curArgs[5], | ||
y: this.curArgs[6], | ||
}); | ||
} | ||
else if (undefined === this.curCommand.rX) { | ||
if (0 > Number(this.curNumber)) { | ||
throw new SyntaxError("Expected positive number, got \"" + this.curNumber + "\" at index \"" + i + "\""); | ||
} | ||
this.curCommand.rX = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.rY) { | ||
if (0 > Number(this.curNumber)) { | ||
throw new SyntaxError("Expected positive number, got \"" + this.curNumber + "\" at index \"" + i + "\""); | ||
} | ||
this.curCommand.rY = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.xRot) { | ||
this.curCommand.xRot = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.lArcFlag) { | ||
if (-1 === FLAGS.indexOf(this.curNumber)) { | ||
throw new SyntaxError("Expected a flag, got \"" + this.curNumber + "\" at index \"" + i + "\""); | ||
} | ||
this.curCommand.lArcFlag = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.sweepFlag) { | ||
if ("0" !== this.curNumber && "1" !== this.curNumber) { | ||
throw new SyntaxError("Expected a flag, got \"" + this.curNumber + "\" at index \"" + i + "\""); | ||
} | ||
this.curCommand.sweepFlag = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} | ||
else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
} | ||
this.curNumber = ""; | ||
// Continue if a white space or a comma was detected | ||
if (-1 !== WSP.indexOf(str[i]) || -1 !== COMMA.indexOf(str[i])) { | ||
continue; | ||
} | ||
// if a sign is detected, then parse the new number | ||
if (-1 !== SIGNS.indexOf(str[i])) { | ||
this.curNumber = str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_INT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
continue; | ||
} | ||
// if the decpoint is detected, then parse the new number | ||
if (-1 !== DECPOINT.indexOf(str[i])) { | ||
this.curNumber = str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_FLOAT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
continue; | ||
} | ||
this.curNumberHasExpDigits = false; | ||
this.curNumberHasExp = false; | ||
this.curNumberHasDecimal = false; | ||
this.canParseCommandOrComma = true; | ||
} | ||
// End of a command | ||
if (-1 !== COMMANDS.indexOf(str[i])) { | ||
// Adding residual command | ||
if (undefined !== this.curCommand) { | ||
if (this.curCommand.invalid) { | ||
throw new SyntaxError("Unterminated command at index " + i + "."); | ||
} | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK; | ||
} | ||
// Continue if a white space or a comma was detected | ||
if (isWhiteSpace(c)) { | ||
continue; | ||
} | ||
// Detecting the next command | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK; | ||
// Is the command relative | ||
if (str[i] === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_RELATIVE; | ||
if ("," === c && this.canParseCommandOrComma) { | ||
// L 0,0, H is not valid: | ||
this.canParseCommandOrComma = false; | ||
continue; | ||
} | ||
else { | ||
this.state ^= this.state & SVGPathDataParser.STATE_RELATIVE; | ||
// if a sign is detected, then parse the new number | ||
if ("+" === c || "-" === c || "." === c) { | ||
this.curNumber = c; | ||
this.curNumberHasDecimal = "." === c; | ||
continue; | ||
} | ||
// Horizontal move to command | ||
if ("z" === str[i].toLowerCase()) { | ||
// Adding residual command | ||
if (0 !== this.curArgs.length) { | ||
throw new SyntaxError("Unterminated command at index " + i + "."); | ||
} | ||
if (!this.canParseCommandOrComma) { | ||
throw new SyntaxError("Unexpected character \"" + c + "\" at index " + i + ". Command cannot follow comma"); | ||
} | ||
this.canParseCommandOrComma = false; | ||
// Detecting the next command | ||
if ("z" === c || "Z" === c) { | ||
commands.push({ | ||
type: SVGPathData_1.SVGPathData.CLOSE_PATH, | ||
}); | ||
this.state = SVGPathDataParser.STATE_COMMAS_WSPS; | ||
this.canParseCommandOrComma = true; | ||
this.curCommandType = -1; | ||
continue; | ||
// Horizontal move to command | ||
} | ||
else if ("h" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_HORIZ_LINE_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.HORIZ_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("h" === c || "H" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.HORIZ_LINE_TO; | ||
this.curCommandRelative = "h" === c; | ||
// Vertical move to command | ||
} | ||
else if ("v" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_VERT_LINE_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.VERT_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("v" === c || "V" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.VERT_LINE_TO; | ||
this.curCommandRelative = "v" === c; | ||
// Move to command | ||
} | ||
else if ("m" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_MOVE_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.MOVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("m" === c || "M" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.MOVE_TO; | ||
this.curCommandRelative = "m" === c; | ||
// Line to command | ||
} | ||
else if ("l" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_LINE_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("l" === c || "L" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.LINE_TO; | ||
this.curCommandRelative = "l" === c; | ||
// Curve to command | ||
} | ||
else if ("c" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_CURVE_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("c" === c || "C" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.CURVE_TO; | ||
this.curCommandRelative = "c" === c; | ||
// Smooth curve to command | ||
} | ||
else if ("s" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_SMOOTH_CURVE_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.SMOOTH_CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("s" === c || "S" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.SMOOTH_CURVE_TO; | ||
this.curCommandRelative = "s" === c; | ||
// Quadratic bezier curve to command | ||
} | ||
else if ("q" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_QUAD_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("q" === c || "Q" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.QUAD_TO; | ||
this.curCommandRelative = "q" === c; | ||
// Smooth quadratic bezier curve to command | ||
} | ||
else if ("t" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_SMOOTH_QUAD_TO; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.SMOOTH_QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
else if ("t" === c || "T" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.SMOOTH_QUAD_TO; | ||
this.curCommandRelative = "t" === c; | ||
// Elliptic arc command | ||
} | ||
else if ("a" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_ARC; | ||
this.curCommand = { | ||
type: SVGPathData_1.SVGPathData.ARC, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
// Unkown command | ||
else if ("a" === c || "A" === c) { | ||
this.curCommandType = SVGPathData_1.SVGPathData.ARC; | ||
this.curCommandRelative = "a" === c; | ||
} | ||
else { | ||
throw new SyntaxError("Unexpected character \"" + str[i] + "\" at index " + i + "."); | ||
throw new SyntaxError("Unexpected character \"" + c + "\" at index " + i + "."); | ||
} | ||
// White spaces can follow a command | ||
this.state |= | ||
SVGPathDataParser.STATE_COMMAS_WSPS | SVGPathDataParser.STATE_NUMBER; | ||
} | ||
@@ -545,43 +303,2 @@ return commands; | ||
}; | ||
// Parsing states | ||
SVGPathDataParser.STATE_WSP = 1; | ||
SVGPathDataParser.STATE_WSPS = 2; | ||
SVGPathDataParser.STATE_COMMA = 4; | ||
SVGPathDataParser.STATE_COMMAS = 8; | ||
SVGPathDataParser.STATE_COMMAS_WSPS = SVGPathDataParser.STATE_WSP | | ||
SVGPathDataParser.STATE_WSPS | | ||
SVGPathDataParser.STATE_COMMA | | ||
SVGPathDataParser.STATE_COMMAS; | ||
SVGPathDataParser.STATE_NUMBER = 16; | ||
SVGPathDataParser.STATE_NUMBER_DIGITS = 32; | ||
SVGPathDataParser.STATE_NUMBER_INT = 64; | ||
SVGPathDataParser.STATE_NUMBER_FLOAT = 128; | ||
SVGPathDataParser.STATE_NUMBER_EXP = 256; | ||
SVGPathDataParser.STATE_NUMBER_EXPSIGN = 512; | ||
SVGPathDataParser.STATE_NUMBER_MASK = SVGPathDataParser.STATE_NUMBER | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS | | ||
SVGPathDataParser.STATE_NUMBER_INT | | ||
SVGPathDataParser.STATE_NUMBER_EXP | | ||
SVGPathDataParser.STATE_NUMBER_FLOAT; | ||
SVGPathDataParser.STATE_RELATIVE = 1024; | ||
SVGPathDataParser.STATE_CLOSE_PATH = 2048; // Close path command (z/Z) | ||
SVGPathDataParser.STATE_MOVE_TO = 4096; // Move to command (m/M) | ||
SVGPathDataParser.STATE_LINE_TO = 8192; // Line to command (l/L=) | ||
SVGPathDataParser.STATE_HORIZ_LINE_TO = 16384; // Horizontal line to command (h/H) | ||
SVGPathDataParser.STATE_VERT_LINE_TO = 32768; // Vertical line to command (v/V) | ||
SVGPathDataParser.STATE_CURVE_TO = 65536; // Curve to command (c/C) | ||
SVGPathDataParser.STATE_SMOOTH_CURVE_TO = 131072; // Smooth curve to command (s/S) | ||
SVGPathDataParser.STATE_QUAD_TO = 262144; // Quadratic bezier curve to command (q/Q) | ||
SVGPathDataParser.STATE_SMOOTH_QUAD_TO = 524288; // Smooth quadratic bezier curve to command (t/T) | ||
SVGPathDataParser.STATE_ARC = 1048576; // Elliptic arc command (a/A) | ||
SVGPathDataParser.STATE_COMMANDS_MASK = SVGPathDataParser.STATE_CLOSE_PATH | | ||
SVGPathDataParser.STATE_MOVE_TO | | ||
SVGPathDataParser.STATE_LINE_TO | | ||
SVGPathDataParser.STATE_HORIZ_LINE_TO | | ||
SVGPathDataParser.STATE_VERT_LINE_TO | | ||
SVGPathDataParser.STATE_CURVE_TO | | ||
SVGPathDataParser.STATE_SMOOTH_CURVE_TO | | ||
SVGPathDataParser.STATE_QUAD_TO | | ||
SVGPathDataParser.STATE_SMOOTH_QUAD_TO | | ||
SVGPathDataParser.STATE_ARC; | ||
return SVGPathDataParser; | ||
@@ -588,0 +305,0 @@ }(TransformableSVG_1.TransformableSVG)); |
{ | ||
"name": "svg-pathdata", | ||
"version": "5.0.0", | ||
"version": "5.0.1", | ||
"description": "Manipulate SVG path data (path[d] attribute content) simply and efficiently.", | ||
@@ -5,0 +5,0 @@ "main": "lib/SVGPathData.js", |
// Parse SVG PathData | ||
// http://www.w3.org/TR/SVG/paths.html#PathDataBNF | ||
import { Transform } from "stream"; | ||
import { SVGCommand, SVGPathData, TransformFunction } from "./SVGPathData"; | ||
import { TransformableSVG } from "./TransformableSVG"; | ||
// Private consts : Char groups | ||
const WSP = [" ", "\t", "\r", "\n"]; | ||
const DIGITS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; | ||
const SIGNS = ["-", "+"]; | ||
const EXPONENTS = ["e", "E"]; | ||
const DECPOINT = ["."]; | ||
const FLAGS = ["0", "1"]; | ||
const COMMA = [","]; | ||
const COMMANDS = [ | ||
"m", | ||
"M", | ||
"z", | ||
"Z", | ||
"l", | ||
"L", | ||
"h", | ||
"H", | ||
"v", | ||
"V", | ||
"c", | ||
"C", | ||
"s", | ||
"S", | ||
"q", | ||
"Q", | ||
"t", | ||
"T", | ||
"a", | ||
"A", | ||
]; | ||
const isWhiteSpace = (c: string) => " " === c || "\t" === c || "\r" === c || "\n" === c; | ||
const isDigit = (c: string) => | ||
"0".charCodeAt(0) <= c.charCodeAt(0) && c.charCodeAt(0) <= "9".charCodeAt(0); | ||
const COMMANDS = "mMzZlLhHvVcCsSqQtTaA"; | ||
// @ts-ignore | ||
const COMMAND_ARG_COUNTS = { | ||
[SVGPathData.MOVE_TO]: 2, | ||
[SVGPathData.LINE_TO]: 2, | ||
[SVGPathData.HORIZ_LINE_TO]: 1, | ||
[SVGPathData.VERT_LINE_TO]: 1, | ||
[SVGPathData.CLOSE_PATH]: 0, | ||
[SVGPathData.QUAD_TO]: 4, | ||
[SVGPathData.SMOOTH_QUAD_TO]: 2, | ||
[SVGPathData.CURVE_TO]: 6, | ||
[SVGPathData.SMOOTH_CURVE_TO]: 4, | ||
[SVGPathData.ARC]: 7, | ||
}; | ||
export class SVGPathDataParser extends TransformableSVG { | ||
curCommand: any = undefined; | ||
state: number = SVGPathDataParser.STATE_COMMAS_WSPS; | ||
curNumber: string = ""; | ||
private curNumber: string = ""; | ||
private curCommandType: SVGCommand["type"] | -1 = -1; | ||
private curCommandRelative = false; | ||
private canParseCommandOrComma = true; | ||
private curNumberHasExp = false; | ||
private curNumberHasExpDigits = false; | ||
private curNumberHasDecimal = false; | ||
private curArgs: number[] = []; | ||
@@ -49,443 +39,215 @@ constructor() { | ||
finish(commands: SVGCommand[] = []) { | ||
const result = this.parse(" ", commands); | ||
this.parse(" ", commands); | ||
// Adding residual command | ||
if (undefined !== this.curCommand) { | ||
if (this.curCommand.invalid) { | ||
throw new SyntaxError("Unterminated command at the path end."); | ||
} | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK; | ||
if (0 !== this.curArgs.length || !this.canParseCommandOrComma) { | ||
throw new SyntaxError("Unterminated command at the path end."); | ||
} | ||
return result; | ||
return commands; | ||
} | ||
parse(str: string, commands: SVGCommand[] = []) { | ||
const finishCommand = (command: SVGCommand) => { | ||
commands.push(command); | ||
this.curArgs.length = 0; | ||
this.canParseCommandOrComma = true; | ||
}; | ||
for (let i = 0; i < str.length; i++) { | ||
const c = str[i]; | ||
// White spaces parsing | ||
if ( | ||
this.state & SVGPathDataParser.STATE_WSP || | ||
this.state & SVGPathDataParser.STATE_WSPS | ||
) { | ||
if (-1 !== WSP.indexOf(str[i])) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_WSP; | ||
// any space stops current number parsing | ||
if ("" !== this.curNumber) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} else { | ||
continue; | ||
} | ||
} | ||
if (isDigit(c)) { | ||
this.curNumber += c; | ||
this.curNumberHasExpDigits = this.curNumberHasExp; | ||
continue; | ||
} | ||
// Commas parsing | ||
if ( | ||
this.state & SVGPathDataParser.STATE_COMMA || | ||
this.state & SVGPathDataParser.STATE_COMMAS | ||
) { | ||
if (-1 !== COMMA.indexOf(str[i])) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMA; | ||
// any comma stops current number parsing | ||
if ("" !== this.curNumber) { | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} else { | ||
continue; | ||
} | ||
} | ||
if ("e" === c || "E" === c) { | ||
this.curNumber += c; | ||
this.curNumberHasExp = true; | ||
continue; | ||
} | ||
// Numbers parsing : -125.25e-125 | ||
if (this.state & SVGPathDataParser.STATE_NUMBER) { | ||
// Reading the sign | ||
if ( | ||
(this.state & SVGPathDataParser.STATE_NUMBER_MASK) === | ||
SVGPathDataParser.STATE_NUMBER | ||
) { | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_INT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
if (-1 !== SIGNS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
continue; | ||
} | ||
if (("-" === c || "+" === c) && this.curNumberHasExp && !this.curNumberHasExpDigits) { | ||
this.curNumber += c; | ||
continue; | ||
} | ||
// if we already have a ".", it means we are starting a new number | ||
if ("." === c && !this.curNumberHasExp && !this.curNumberHasDecimal) { | ||
this.curNumber += c; | ||
this.curNumberHasDecimal = true; | ||
continue; | ||
} | ||
// New number | ||
if (this.curNumber && -1 !== this.curCommandType) { | ||
const val = Number(this.curNumber); | ||
if (isNaN(val)) { | ||
throw new SyntaxError(`Invalid number ending at ${i}`); | ||
} | ||
// Reading the exponent sign | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_EXPSIGN) { | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_EXPSIGN; | ||
this.state |= SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
if (-1 !== SIGNS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
continue; | ||
if (this.curCommandType === SVGPathData.ARC) { | ||
if (0 === this.curArgs.length || 1 === this.curArgs.length) { | ||
if (0 > val) { | ||
throw new SyntaxError(`Expected positive number, got "${val}" at index "${i}"`); | ||
} | ||
} else if (3 === this.curArgs.length || 4 === this.curArgs.length) { | ||
if ("0" !== this.curNumber && "1" !== this.curNumber) { | ||
throw new SyntaxError(`Expected a flag, got "${this.curNumber}" at index "${i}"`); | ||
} | ||
} | ||
} | ||
// Reading digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_DIGITS) { | ||
if (-1 !== DIGITS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
continue; | ||
} | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
} | ||
// Ended reading left side digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_INT) { | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_INT; | ||
// if got a point, reading right side digits | ||
if (-1 !== DECPOINT.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_FLOAT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
continue; | ||
// if got e/E, reading the exponent | ||
} else if (-1 !== EXPONENTS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_EXP | | ||
SVGPathDataParser.STATE_NUMBER_EXPSIGN; | ||
continue; | ||
} | ||
// else we"re done with that number | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
// Ended reading decimal digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_FLOAT) { | ||
this.state ^= SVGPathDataParser.STATE_NUMBER_FLOAT; | ||
// if got e/E, reading the exponent | ||
if (-1 !== EXPONENTS.indexOf(str[i])) { | ||
this.curNumber += str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_EXP | | ||
SVGPathDataParser.STATE_NUMBER_EXPSIGN; | ||
continue; | ||
} | ||
// else we"re done with that number | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
// Ended reading exponent digits | ||
if (this.state & SVGPathDataParser.STATE_NUMBER_EXP) { | ||
// we"re done with that number | ||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK; | ||
} | ||
} | ||
// New number | ||
if (this.curNumber) { | ||
// Horizontal move to command (x) | ||
if (this.state & SVGPathDataParser.STATE_HORIZ_LINE_TO) { | ||
if (undefined === this.curCommand) { | ||
commands.push({ | ||
this.curArgs.push(val); | ||
if (this.curArgs.length === COMMAND_ARG_COUNTS[this.curCommandType]) { | ||
if (SVGPathData.HORIZ_LINE_TO === this.curCommandType) { | ||
finishCommand({ | ||
type: SVGPathData.HORIZ_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
x: Number(this.curNumber), | ||
relative: this.curCommandRelative, | ||
x: val, | ||
}); | ||
} else { | ||
this.curCommand.x = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Vertical move to command (y) | ||
} else if (this.state & SVGPathDataParser.STATE_VERT_LINE_TO) { | ||
if (undefined === this.curCommand) { | ||
commands.push({ | ||
} else if (SVGPathData.VERT_LINE_TO === this.curCommandType) { | ||
finishCommand({ | ||
type: SVGPathData.VERT_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
y: Number(this.curNumber), | ||
relative: this.curCommandRelative, | ||
y: val, | ||
}); | ||
} else { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Move to / line to / smooth quadratic curve to commands (x, y) | ||
} else if ( | ||
this.state & SVGPathDataParser.STATE_MOVE_TO || | ||
this.state & SVGPathDataParser.STATE_LINE_TO || | ||
this.state & SVGPathDataParser.STATE_SMOOTH_QUAD_TO | ||
) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
type: | ||
this.state & SVGPathDataParser.STATE_MOVE_TO | ||
? SVGPathData.MOVE_TO | ||
: this.state & SVGPathDataParser.STATE_LINE_TO | ||
? SVGPathData.LINE_TO | ||
: SVGPathData.SMOOTH_QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
x: Number(this.curNumber), | ||
}; | ||
} else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} else { | ||
delete this.curCommand.invalid; | ||
this.curCommand.y = Number(this.curNumber); | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
// Move to / line to / smooth quadratic curve to commands (x, y) | ||
} else if ( | ||
this.curCommandType === SVGPathData.MOVE_TO || | ||
this.curCommandType === SVGPathData.LINE_TO || | ||
this.curCommandType === SVGPathData.SMOOTH_QUAD_TO | ||
) { | ||
finishCommand({ | ||
type: this.curCommandType, | ||
relative: this.curCommandRelative, | ||
x: this.curArgs[0], | ||
y: this.curArgs[1], | ||
} as SVGCommand); | ||
// Switch to line to state | ||
if (this.state & SVGPathDataParser.STATE_MOVE_TO) { | ||
this.state ^= SVGPathDataParser.STATE_MOVE_TO; | ||
this.state |= SVGPathDataParser.STATE_LINE_TO; | ||
if (SVGPathData.MOVE_TO === this.curCommandType) { | ||
this.curCommandType = SVGPathData.LINE_TO; | ||
} | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Curve to commands (x1, y1, x2, y2, x, y) | ||
} else if (this.state & SVGPathDataParser.STATE_CURVE_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
} else if (this.curCommandType === SVGPathData.CURVE_TO) { | ||
finishCommand({ | ||
type: SVGPathData.CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
x1: Number(this.curNumber), | ||
}; | ||
} else if (undefined === this.curCommand.x1) { | ||
this.curCommand.x1 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y1) { | ||
this.curCommand.y1 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.x2) { | ||
this.curCommand.x2 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y2) { | ||
this.curCommand.y2 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Smooth curve to commands (x1, y1, x, y) | ||
} else if (this.state & SVGPathDataParser.STATE_SMOOTH_CURVE_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
relative: this.curCommandRelative, | ||
x1: this.curArgs[0], | ||
y1: this.curArgs[1], | ||
x2: this.curArgs[2], | ||
y2: this.curArgs[3], | ||
x: this.curArgs[4], | ||
y: this.curArgs[5], | ||
}); | ||
} else if (this.curCommandType === SVGPathData.SMOOTH_CURVE_TO) { | ||
finishCommand({ | ||
type: SVGPathData.SMOOTH_CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
x2: Number(this.curNumber), | ||
}; | ||
} else if (undefined === this.curCommand.x2) { | ||
this.curCommand.x2 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y2) { | ||
this.curCommand.y2 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Quadratic bezier curve to commands (x1, y1, x, y) | ||
} else if (this.state & SVGPathDataParser.STATE_QUAD_TO) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
relative: this.curCommandRelative, | ||
x2: this.curArgs[0], | ||
y2: this.curArgs[1], | ||
x: this.curArgs[2], | ||
y: this.curArgs[3], | ||
}); | ||
} else if (this.curCommandType === SVGPathData.QUAD_TO) { | ||
finishCommand({ | ||
type: SVGPathData.QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
x1: Number(this.curNumber), | ||
}; | ||
} else if (undefined === this.curCommand.x1) { | ||
this.curCommand.x1 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y1) { | ||
this.curCommand.y1 = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
// Elliptic arc commands (rX, rY, xRot, lArcFlag, sweepFlag, x, y) | ||
} else if (this.state & SVGPathDataParser.STATE_ARC) { | ||
if (undefined === this.curCommand) { | ||
this.curCommand = { | ||
relative: this.curCommandRelative, | ||
x1: this.curArgs[0], | ||
y1: this.curArgs[1], | ||
x: this.curArgs[2], | ||
y: this.curArgs[3], | ||
}); | ||
} else if (this.curCommandType === SVGPathData.ARC) { | ||
finishCommand({ | ||
type: SVGPathData.ARC, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
rX: Number(this.curNumber), | ||
}; | ||
} else if (undefined === this.curCommand.rX) { | ||
if (0 > Number(this.curNumber)) { | ||
throw new SyntaxError( | ||
`Expected positive number, got "${ | ||
this.curNumber | ||
}" at index "${i}"`, | ||
); | ||
} | ||
this.curCommand.rX = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.rY) { | ||
if (0 > Number(this.curNumber)) { | ||
throw new SyntaxError( | ||
`Expected positive number, got "${ | ||
this.curNumber | ||
}" at index "${i}"`, | ||
); | ||
} | ||
this.curCommand.rY = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.xRot) { | ||
this.curCommand.xRot = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.lArcFlag) { | ||
if (-1 === FLAGS.indexOf(this.curNumber)) { | ||
throw new SyntaxError( | ||
`Expected a flag, got "${this.curNumber}" at index "${i}"`, | ||
); | ||
} | ||
this.curCommand.lArcFlag = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.sweepFlag) { | ||
if ("0" !== this.curNumber && "1" !== this.curNumber) { | ||
throw new SyntaxError( | ||
`Expected a flag, got "${this.curNumber}" at index "${i}"`, | ||
); | ||
} | ||
this.curCommand.sweepFlag = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.x) { | ||
this.curCommand.x = Number(this.curNumber); | ||
} else if (undefined === this.curCommand.y) { | ||
this.curCommand.y = Number(this.curNumber); | ||
delete this.curCommand.invalid; | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
relative: this.curCommandRelative, | ||
rX: this.curArgs[0], | ||
rY: this.curArgs[1], | ||
xRot: this.curArgs[2], | ||
lArcFlag: this.curArgs[3] as 0 | 1, | ||
sweepFlag: this.curArgs[4] as 0 | 1, | ||
x: this.curArgs[5], | ||
y: this.curArgs[6], | ||
}); | ||
} | ||
this.state |= SVGPathDataParser.STATE_NUMBER; | ||
} | ||
this.curNumber = ""; | ||
// Continue if a white space or a comma was detected | ||
if (-1 !== WSP.indexOf(str[i]) || -1 !== COMMA.indexOf(str[i])) { | ||
continue; | ||
} | ||
// if a sign is detected, then parse the new number | ||
if (-1 !== SIGNS.indexOf(str[i])) { | ||
this.curNumber = str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_INT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
continue; | ||
} | ||
// if the decpoint is detected, then parse the new number | ||
if (-1 !== DECPOINT.indexOf(str[i])) { | ||
this.curNumber = str[i]; | ||
this.state |= | ||
SVGPathDataParser.STATE_NUMBER_FLOAT | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS; | ||
continue; | ||
} | ||
this.curNumberHasExpDigits = false; | ||
this.curNumberHasExp = false; | ||
this.curNumberHasDecimal = false; | ||
this.canParseCommandOrComma = true; | ||
} | ||
// End of a command | ||
if (-1 !== COMMANDS.indexOf(str[i])) { | ||
// Adding residual command | ||
if (undefined !== this.curCommand) { | ||
if (this.curCommand.invalid) { | ||
throw new SyntaxError(`Unterminated command at index ${i}.`); | ||
} | ||
commands.push(this.curCommand); | ||
this.curCommand = undefined; | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK; | ||
} | ||
// Continue if a white space or a comma was detected | ||
if (isWhiteSpace(c)) { | ||
continue; | ||
} | ||
if ("," === c && this.canParseCommandOrComma) { | ||
// L 0,0, H is not valid: | ||
this.canParseCommandOrComma = false; | ||
continue; | ||
} | ||
// if a sign is detected, then parse the new number | ||
if ("+" === c || "-" === c || "." === c) { | ||
this.curNumber = c; | ||
this.curNumberHasDecimal = "." === c; | ||
continue; | ||
} | ||
// Adding residual command | ||
if (0 !== this.curArgs.length) { | ||
throw new SyntaxError(`Unterminated command at index ${i}.`); | ||
} | ||
if (!this.canParseCommandOrComma) { | ||
throw new SyntaxError(`Unexpected character "${c}" at index ${i}. Command cannot follow comma`); | ||
} | ||
this.canParseCommandOrComma = false; | ||
// Detecting the next command | ||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK; | ||
// Is the command relative | ||
if (str[i] === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_RELATIVE; | ||
} else { | ||
this.state ^= this.state & SVGPathDataParser.STATE_RELATIVE; | ||
} | ||
// Horizontal move to command | ||
if ("z" === str[i].toLowerCase()) { | ||
if ("z" === c || "Z" === c) { | ||
commands.push({ | ||
type: SVGPathData.CLOSE_PATH, | ||
}); | ||
this.state = SVGPathDataParser.STATE_COMMAS_WSPS; | ||
this.canParseCommandOrComma = true; | ||
this.curCommandType = -1; | ||
continue; | ||
// Horizontal move to command | ||
} else if ("h" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_HORIZ_LINE_TO; | ||
this.curCommand = { | ||
type: SVGPathData.HORIZ_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("h" === c || "H" === c) { | ||
this.curCommandType = SVGPathData.HORIZ_LINE_TO; | ||
this.curCommandRelative = "h" === c; | ||
// Vertical move to command | ||
} else if ("v" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_VERT_LINE_TO; | ||
this.curCommand = { | ||
type: SVGPathData.VERT_LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("v" === c || "V" === c) { | ||
this.curCommandType = SVGPathData.VERT_LINE_TO; | ||
this.curCommandRelative = "v" === c; | ||
// Move to command | ||
} else if ("m" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_MOVE_TO; | ||
this.curCommand = { | ||
type: SVGPathData.MOVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("m" === c || "M" === c) { | ||
this.curCommandType = SVGPathData.MOVE_TO; | ||
this.curCommandRelative = "m" === c; | ||
// Line to command | ||
} else if ("l" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_LINE_TO; | ||
this.curCommand = { | ||
type: SVGPathData.LINE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("l" === c || "L" === c) { | ||
this.curCommandType = SVGPathData.LINE_TO; | ||
this.curCommandRelative = "l" === c; | ||
// Curve to command | ||
} else if ("c" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_CURVE_TO; | ||
this.curCommand = { | ||
type: SVGPathData.CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("c" === c || "C" === c) { | ||
this.curCommandType = SVGPathData.CURVE_TO; | ||
this.curCommandRelative = "c" === c; | ||
// Smooth curve to command | ||
} else if ("s" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_SMOOTH_CURVE_TO; | ||
this.curCommand = { | ||
type: SVGPathData.SMOOTH_CURVE_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("s" === c || "S" === c) { | ||
this.curCommandType = SVGPathData.SMOOTH_CURVE_TO; | ||
this.curCommandRelative = "s" === c; | ||
// Quadratic bezier curve to command | ||
} else if ("q" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_QUAD_TO; | ||
this.curCommand = { | ||
type: SVGPathData.QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("q" === c || "Q" === c) { | ||
this.curCommandType = SVGPathData.QUAD_TO; | ||
this.curCommandRelative = "q" === c; | ||
// Smooth quadratic bezier curve to command | ||
} else if ("t" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_SMOOTH_QUAD_TO; | ||
this.curCommand = { | ||
type: SVGPathData.SMOOTH_QUAD_TO, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
} else if ("t" === c || "T" === c) { | ||
this.curCommandType = SVGPathData.SMOOTH_QUAD_TO; | ||
this.curCommandRelative = "t" === c; | ||
// Elliptic arc command | ||
} else if ("a" === str[i].toLowerCase()) { | ||
this.state |= SVGPathDataParser.STATE_ARC; | ||
this.curCommand = { | ||
type: SVGPathData.ARC, | ||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE), | ||
invalid: true, | ||
}; | ||
// Unkown command | ||
} else if ("a" === c || "A" === c) { | ||
this.curCommandType = SVGPathData.ARC; | ||
this.curCommandRelative = "a" === c; | ||
} else { | ||
throw new SyntaxError( | ||
`Unexpected character "${str[i]}" at index ${i}.`, | ||
); | ||
throw new SyntaxError(`Unexpected character "${c}" at index ${i}.`); | ||
} | ||
// White spaces can follow a command | ||
this.state |= | ||
SVGPathDataParser.STATE_COMMAS_WSPS | SVGPathDataParser.STATE_NUMBER; | ||
} | ||
return commands; | ||
} | ||
/** | ||
* Return a wrapper around this parser which applies the transformation on parsed commands. | ||
*/ | ||
/** | ||
* Return a wrapper around this parser which applies the transformation on parsed commands. | ||
*/ | ||
transform(transform: TransformFunction) { | ||
@@ -495,3 +257,6 @@ const result = Object.create(this, { | ||
value(chunk: string, commands: SVGCommand[] = []) { | ||
const parsedCommands = Object.getPrototypeOf(this).parse.call(this, chunk); | ||
const parsedCommands = Object.getPrototypeOf(this).parse.call( | ||
this, | ||
chunk, | ||
); | ||
for (const c of parsedCommands) { | ||
@@ -511,44 +276,2 @@ const cT = transform(c); | ||
} | ||
// Parsing states | ||
static readonly STATE_WSP = 1; | ||
static readonly STATE_WSPS = 2; | ||
static readonly STATE_COMMA = 4; | ||
static readonly STATE_COMMAS = 8; | ||
static readonly STATE_COMMAS_WSPS = SVGPathDataParser.STATE_WSP | | ||
SVGPathDataParser.STATE_WSPS | | ||
SVGPathDataParser.STATE_COMMA | | ||
SVGPathDataParser.STATE_COMMAS; | ||
static readonly STATE_NUMBER = 16; | ||
static readonly STATE_NUMBER_DIGITS = 32; | ||
static readonly STATE_NUMBER_INT = 64; | ||
static readonly STATE_NUMBER_FLOAT = 128; | ||
static readonly STATE_NUMBER_EXP = 256; | ||
static readonly STATE_NUMBER_EXPSIGN = 512; | ||
static readonly STATE_NUMBER_MASK = SVGPathDataParser.STATE_NUMBER | | ||
SVGPathDataParser.STATE_NUMBER_DIGITS | | ||
SVGPathDataParser.STATE_NUMBER_INT | | ||
SVGPathDataParser.STATE_NUMBER_EXP | | ||
SVGPathDataParser.STATE_NUMBER_FLOAT; | ||
static readonly STATE_RELATIVE = 1024; | ||
static readonly STATE_CLOSE_PATH = 2048; // Close path command (z/Z) | ||
static readonly STATE_MOVE_TO = 4096; // Move to command (m/M) | ||
static readonly STATE_LINE_TO = 8192; // Line to command (l/L=) | ||
static readonly STATE_HORIZ_LINE_TO = 16384; // Horizontal line to command (h/H) | ||
static readonly STATE_VERT_LINE_TO = 32768; // Vertical line to command (v/V) | ||
static readonly STATE_CURVE_TO = 65536; // Curve to command (c/C) | ||
static readonly STATE_SMOOTH_CURVE_TO = 131072; // Smooth curve to command (s/S) | ||
static readonly STATE_QUAD_TO = 262144; // Quadratic bezier curve to command (q/Q) | ||
static readonly STATE_SMOOTH_QUAD_TO = 524288; // Smooth quadratic bezier curve to command (t/T) | ||
static readonly STATE_ARC = 1048576; // Elliptic arc command (a/A) | ||
static readonly STATE_COMMANDS_MASK = SVGPathDataParser.STATE_CLOSE_PATH | | ||
SVGPathDataParser.STATE_MOVE_TO | | ||
SVGPathDataParser.STATE_LINE_TO | | ||
SVGPathDataParser.STATE_HORIZ_LINE_TO | | ||
SVGPathDataParser.STATE_VERT_LINE_TO | | ||
SVGPathDataParser.STATE_CURVE_TO | | ||
SVGPathDataParser.STATE_SMOOTH_CURVE_TO | | ||
SVGPathDataParser.STATE_QUAD_TO | | ||
SVGPathDataParser.STATE_SMOOTH_QUAD_TO | | ||
SVGPathDataParser.STATE_ARC; | ||
} |
@@ -11,9 +11,9 @@ /* eslint-disable no-new */ | ||
it('should not work when badly declared', () => { | ||
// assert.throw(() => { | ||
// new SVGPathData('A'); | ||
// }, SyntaxError, 'Unterminated command at the path end.'); | ||
// assert.throw(() => { | ||
// new SVGPathData('A 30'); | ||
// }, SyntaxError, 'Unterminated command at the path end.'); | ||
assert.throw(() => { | ||
new SVGPathData('A'); | ||
}, SyntaxError, 'Unterminated command at the path end.'); | ||
assert.throw(() => { | ||
new SVGPathData('A 30'); | ||
}, SyntaxError, 'Unterminated command at the path end.'); | ||
assert.throw(() => { | ||
new SVGPathData('A 30 50'); | ||
@@ -40,4 +40,4 @@ }, SyntaxError, 'Unterminated command at the path end.'); | ||
assert.throw(() => { | ||
new SVGPathData('A,-30,50,0,0,1,162.55,162.45'); | ||
}, SyntaxError, 'Expected positive number, got "-30" at index "5"'); | ||
new SVGPathData('A-30,50,0,0,1,162.55,162.45'); | ||
}, SyntaxError, 'Expected positive number, got "-30" at index "4"'); | ||
}); | ||
@@ -47,4 +47,4 @@ | ||
assert.throw(() => { | ||
new SVGPathData('A,30,-50,0,0,1,162.55,162.45'); | ||
}, SyntaxError, 'Expected positive number, got "-50" at index "8"'); | ||
new SVGPathData('A30,-50,0,0,1,162.55,162.45'); | ||
}, SyntaxError, 'Expected positive number, got "-50" at index "7"'); | ||
}); | ||
@@ -54,4 +54,4 @@ | ||
assert.throw(() => { | ||
new SVGPathData('A,30,50,0,15,1,162.55,162.45'); | ||
}, SyntaxError, 'Expected a flag, got "15" at index "12"'); | ||
new SVGPathData('A30,50,0,15,1,162.55,162.45'); | ||
}, SyntaxError, 'Expected a flag, got "15" at index "11"'); | ||
}); | ||
@@ -61,8 +61,8 @@ | ||
assert.throw(() => { | ||
new SVGPathData('A,30,50,0,0,15,162.55,162.45'); | ||
}, SyntaxError, 'Expected a flag, got "15" at index "14"'); | ||
new SVGPathData('A30,50,0,0,15,162.55,162.45'); | ||
}, SyntaxError, 'Expected a flag, got "15" at index "13"'); | ||
}); | ||
it('should work with comma separated coordinates', () => { | ||
const commands = new SVGPathData('A,30,50,0,0,1,162.55,162.45').commands; | ||
const commands = new SVGPathData('A 30,50,0,0,1,162.55,162.45').commands; | ||
@@ -79,2 +79,5 @@ assert.equal(commands[0].type, SVGPathData.ARC); | ||
}); | ||
it('should not work with a comma immediately after A', () => { | ||
assert.throw(() => new SVGPathData('A,30,50,0,0,1,162.55,162.45')); | ||
}); | ||
@@ -81,0 +84,0 @@ it('should work with space separated coordinates', () => { |
@@ -28,3 +28,3 @@ /* eslint max-len:0 */ | ||
it('should work before a command sequence', () => { | ||
const commands = new SVGPathData(' Z M10,10 L10,10, H10, V10').commands; | ||
const commands = new SVGPathData(' Z M10,10 L10,10 H10 V10').commands; | ||
@@ -35,3 +35,3 @@ assert.equal(commands[0].type, SVGPathData.CLOSE_PATH); | ||
it('should work after a command sequence', () => { | ||
const commands = new SVGPathData('M10,10 L10,10, H10, V10 Z').commands; | ||
const commands = new SVGPathData('M10,10 L10,10 H10 V10 Z').commands; | ||
@@ -42,3 +42,3 @@ assert.equal(commands[4].type, SVGPathData.CLOSE_PATH); | ||
it('should work in a command sequence', () => { | ||
const commands = new SVGPathData('M10,10 L10,10, H10, V10 Z M10,10 L10,10, H10, V10').commands; | ||
const commands = new SVGPathData('M10,10 L10,10 H10 V10 Z M10,10 L10,10 H10 V10').commands; | ||
@@ -45,0 +45,0 @@ assert.equal(commands[4].type, SVGPathData.CLOSE_PATH); |
@@ -221,3 +221,3 @@ /* eslint max-len:0 */ | ||
const commands = new SVGPathData( | ||
'V100H100v0.12h0.12,V100,h100v-10e-5 H-10e-5').commands; | ||
'V100H100v0.12h0.12V100h100v-10e-5 H-10e-5').commands; | ||
@@ -224,0 +224,0 @@ assert.equal(commands[0].type, SVGPathData.VERT_LINE_TO); |
@@ -93,2 +93,7 @@ /* eslint max-len:0 */ | ||
it('should fail with eE', () => { | ||
assert.throws(() => new SVGPathData('H1ee2')); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
83
425570
6349