├── .gitignore ├── .jshintrc ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── flatten.js ├── lib.js ├── parse.js ├── pathify.js └── transform.js └── test ├── flatten.spec.js ├── lib-samples.spec.js ├── lib.spec.js ├── parse.spec.js ├── pathify.spec.js ├── samples ├── sample1.svg ├── sample1_result.svg ├── sample2.svg ├── sample2_result.svg ├── sample3.svg └── sample3_result.svg └── transform.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directories 2 | node_modules 3 | jspm_packages 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 8 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 8 5 | - 14 6 | - lts/* 7 | 8 | scripts: 9 | - npm test 10 | - npm run lint 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016 StadLine 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 | OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | svg-flatten 2 | ========================================================================================== 3 | 4 | Turns SVG shapes (polygon, polyline, rect, g) into SVG paths. It can merge groups and apply transforms. 5 | 6 | How to use? 7 | ----------- 8 | 9 | ```js 10 | const svgFlatten = require('svg-flatten') 11 | const fs = require('fs') 12 | 13 | let flattendSvgPath = 'tmp-flattened.svg' 14 | 15 | // read SVG file into string 16 | let svgString = fs.readFileSync('circle-rect.svg', 'utf8') 17 | // convert all objects to paths 18 | let modifiedSvgString = svgFlatten(svgString).pathify().value() 19 | // write SVG string to disk 20 | fs.writeFileSync(flattendSvgPath,modifiedSvgString) 21 | ``` 22 | 23 | API 24 | --- 25 | 26 | ### svgFlatten(content: string): SvgFlatten 27 | 28 | Reads SVG content and creates a SvgFlatten instance. 29 | 30 | ### .pathify(): SvgFlatten 31 | 32 | Turns SVG shapes (polygon, polyline, rect, g) into SVG paths. It is **needed** before other transformations. 33 | 34 | ### .flatten(): SvgFlatten 35 | 36 | Converts groups of paths to a fat path, combining all child paths into one. 37 | 38 | **Be careful: it tries to squash the xml structure, information can be lost.** 39 | 40 | Some example of the limitations: 41 | - duplicate attributes cannot be safely squashed, like the id in `` 42 | - style rules based on the structure like `#g1 > circle` 43 | - [`use`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use) directive may not apply 44 | 45 | ### .transform(): SvgFlatten 46 | 47 | Apply [SVG transformations](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform) to paths. It doesn't apply clipPath. 48 | 49 | ### .value(): string 50 | 51 | Returns the final result as SVG content. 52 | 53 | Need more info? 54 | --------------- 55 | 56 | Sadly, I wrote this lib for an old project (2016) and didn't need to tweak it since. It is not actively maintened, but I'll try to watch pull-requests. 57 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svg-flatten", 3 | "version": "1.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "assertion-error": { 8 | "version": "1.1.0", 9 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 10 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 11 | "dev": true 12 | }, 13 | "available-typed-arrays": { 14 | "version": "1.0.5", 15 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 16 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 17 | "dev": true 18 | }, 19 | "balanced-match": { 20 | "version": "1.0.2", 21 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 22 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 23 | "dev": true 24 | }, 25 | "brace-expansion": { 26 | "version": "1.1.11", 27 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 28 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 29 | "dev": true, 30 | "requires": { 31 | "balanced-match": "^1.0.0", 32 | "concat-map": "0.0.1" 33 | } 34 | }, 35 | "call-bind": { 36 | "version": "1.0.2", 37 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 38 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 39 | "dev": true, 40 | "requires": { 41 | "function-bind": "^1.1.1", 42 | "get-intrinsic": "^1.0.2" 43 | } 44 | }, 45 | "chai": { 46 | "version": "3.5.0", 47 | "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", 48 | "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", 49 | "dev": true, 50 | "requires": { 51 | "assertion-error": "^1.0.1", 52 | "deep-eql": "^0.1.3", 53 | "type-detect": "^1.0.0" 54 | } 55 | }, 56 | "cli": { 57 | "version": "1.0.1", 58 | "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", 59 | "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", 60 | "dev": true, 61 | "requires": { 62 | "exit": "0.1.2", 63 | "glob": "^7.1.1" 64 | }, 65 | "dependencies": { 66 | "glob": { 67 | "version": "7.2.0", 68 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 69 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 70 | "dev": true, 71 | "requires": { 72 | "fs.realpath": "^1.0.0", 73 | "inflight": "^1.0.4", 74 | "inherits": "2", 75 | "minimatch": "^3.0.4", 76 | "once": "^1.3.0", 77 | "path-is-absolute": "^1.0.0" 78 | } 79 | }, 80 | "minimatch": { 81 | "version": "3.1.2", 82 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 83 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 84 | "dev": true, 85 | "requires": { 86 | "brace-expansion": "^1.1.7" 87 | } 88 | } 89 | } 90 | }, 91 | "commander": { 92 | "version": "2.3.0", 93 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", 94 | "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", 95 | "dev": true 96 | }, 97 | "concat-map": { 98 | "version": "0.0.1", 99 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 100 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 101 | "dev": true 102 | }, 103 | "console-browserify": { 104 | "version": "1.1.0", 105 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", 106 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", 107 | "dev": true, 108 | "requires": { 109 | "date-now": "^0.1.4" 110 | } 111 | }, 112 | "core-util-is": { 113 | "version": "1.0.3", 114 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 115 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 116 | "dev": true 117 | }, 118 | "date-now": { 119 | "version": "0.1.4", 120 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", 121 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", 122 | "dev": true 123 | }, 124 | "debug": { 125 | "version": "2.2.0", 126 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 127 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 128 | "dev": true, 129 | "requires": { 130 | "ms": "0.7.1" 131 | } 132 | }, 133 | "deep-eql": { 134 | "version": "0.1.3", 135 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", 136 | "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", 137 | "dev": true, 138 | "requires": { 139 | "type-detect": "0.1.1" 140 | }, 141 | "dependencies": { 142 | "type-detect": { 143 | "version": "0.1.1", 144 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", 145 | "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", 146 | "dev": true 147 | } 148 | } 149 | }, 150 | "define-properties": { 151 | "version": "1.1.4", 152 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", 153 | "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", 154 | "dev": true, 155 | "requires": { 156 | "has-property-descriptors": "^1.0.0", 157 | "object-keys": "^1.1.1" 158 | } 159 | }, 160 | "diff": { 161 | "version": "1.4.0", 162 | "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", 163 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", 164 | "dev": true 165 | }, 166 | "dom-serializer": { 167 | "version": "0.2.2", 168 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", 169 | "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", 170 | "dev": true, 171 | "requires": { 172 | "domelementtype": "^2.0.1", 173 | "entities": "^2.0.0" 174 | }, 175 | "dependencies": { 176 | "domelementtype": { 177 | "version": "2.3.0", 178 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", 179 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", 180 | "dev": true 181 | }, 182 | "entities": { 183 | "version": "2.2.0", 184 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", 185 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", 186 | "dev": true 187 | } 188 | } 189 | }, 190 | "domelementtype": { 191 | "version": "1.3.1", 192 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", 193 | "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", 194 | "dev": true 195 | }, 196 | "domhandler": { 197 | "version": "2.3.0", 198 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", 199 | "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", 200 | "dev": true, 201 | "requires": { 202 | "domelementtype": "1" 203 | } 204 | }, 205 | "domutils": { 206 | "version": "1.5.1", 207 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", 208 | "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", 209 | "dev": true, 210 | "requires": { 211 | "dom-serializer": "0", 212 | "domelementtype": "1" 213 | } 214 | }, 215 | "entities": { 216 | "version": "1.0.0", 217 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", 218 | "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", 219 | "dev": true 220 | }, 221 | "es-abstract": { 222 | "version": "1.19.5", 223 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", 224 | "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", 225 | "dev": true, 226 | "requires": { 227 | "call-bind": "^1.0.2", 228 | "es-to-primitive": "^1.2.1", 229 | "function-bind": "^1.1.1", 230 | "get-intrinsic": "^1.1.1", 231 | "get-symbol-description": "^1.0.0", 232 | "has": "^1.0.3", 233 | "has-symbols": "^1.0.3", 234 | "internal-slot": "^1.0.3", 235 | "is-callable": "^1.2.4", 236 | "is-negative-zero": "^2.0.2", 237 | "is-regex": "^1.1.4", 238 | "is-shared-array-buffer": "^1.0.2", 239 | "is-string": "^1.0.7", 240 | "is-weakref": "^1.0.2", 241 | "object-inspect": "^1.12.0", 242 | "object-keys": "^1.1.1", 243 | "object.assign": "^4.1.2", 244 | "string.prototype.trimend": "^1.0.4", 245 | "string.prototype.trimstart": "^1.0.4", 246 | "unbox-primitive": "^1.0.1" 247 | } 248 | }, 249 | "es-to-primitive": { 250 | "version": "1.2.1", 251 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 252 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 253 | "dev": true, 254 | "requires": { 255 | "is-callable": "^1.1.4", 256 | "is-date-object": "^1.0.1", 257 | "is-symbol": "^1.0.2" 258 | } 259 | }, 260 | "escape-string-regexp": { 261 | "version": "1.0.2", 262 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", 263 | "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", 264 | "dev": true 265 | }, 266 | "exit": { 267 | "version": "0.1.2", 268 | "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", 269 | "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", 270 | "dev": true 271 | }, 272 | "fill-keys": { 273 | "version": "1.0.2", 274 | "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", 275 | "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", 276 | "dev": true, 277 | "requires": { 278 | "is-object": "~1.0.1", 279 | "merge-descriptors": "~1.0.0" 280 | } 281 | }, 282 | "foreach": { 283 | "version": "2.0.5", 284 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", 285 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", 286 | "dev": true 287 | }, 288 | "formatio": { 289 | "version": "1.1.1", 290 | "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", 291 | "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", 292 | "dev": true, 293 | "requires": { 294 | "samsam": "~1.1" 295 | } 296 | }, 297 | "fs.realpath": { 298 | "version": "1.0.0", 299 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 300 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 301 | "dev": true 302 | }, 303 | "function-bind": { 304 | "version": "1.1.1", 305 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 306 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 307 | "dev": true 308 | }, 309 | "get-intrinsic": { 310 | "version": "1.1.1", 311 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", 312 | "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", 313 | "dev": true, 314 | "requires": { 315 | "function-bind": "^1.1.1", 316 | "has": "^1.0.3", 317 | "has-symbols": "^1.0.1" 318 | } 319 | }, 320 | "get-symbol-description": { 321 | "version": "1.0.0", 322 | "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", 323 | "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", 324 | "dev": true, 325 | "requires": { 326 | "call-bind": "^1.0.2", 327 | "get-intrinsic": "^1.1.1" 328 | } 329 | }, 330 | "glob": { 331 | "version": "3.2.11", 332 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 333 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 334 | "dev": true, 335 | "requires": { 336 | "inherits": "2", 337 | "minimatch": "0.3" 338 | } 339 | }, 340 | "growl": { 341 | "version": "1.9.2", 342 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 343 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 344 | "dev": true 345 | }, 346 | "has": { 347 | "version": "1.0.3", 348 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 349 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 350 | "dev": true, 351 | "requires": { 352 | "function-bind": "^1.1.1" 353 | } 354 | }, 355 | "has-bigints": { 356 | "version": "1.0.1", 357 | "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", 358 | "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", 359 | "dev": true 360 | }, 361 | "has-property-descriptors": { 362 | "version": "1.0.0", 363 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 364 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 365 | "dev": true, 366 | "requires": { 367 | "get-intrinsic": "^1.1.1" 368 | } 369 | }, 370 | "has-symbols": { 371 | "version": "1.0.3", 372 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 373 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 374 | "dev": true 375 | }, 376 | "has-tostringtag": { 377 | "version": "1.0.0", 378 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 379 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 380 | "dev": true, 381 | "requires": { 382 | "has-symbols": "^1.0.2" 383 | } 384 | }, 385 | "htmlparser2": { 386 | "version": "3.8.3", 387 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", 388 | "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", 389 | "dev": true, 390 | "requires": { 391 | "domelementtype": "1", 392 | "domhandler": "2.3", 393 | "domutils": "1.5", 394 | "entities": "1.0", 395 | "readable-stream": "1.1" 396 | } 397 | }, 398 | "inflight": { 399 | "version": "1.0.6", 400 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 401 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 402 | "dev": true, 403 | "requires": { 404 | "once": "^1.3.0", 405 | "wrappy": "1" 406 | } 407 | }, 408 | "inherits": { 409 | "version": "2.0.4", 410 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 411 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 412 | "dev": true 413 | }, 414 | "internal-slot": { 415 | "version": "1.0.3", 416 | "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", 417 | "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", 418 | "dev": true, 419 | "requires": { 420 | "get-intrinsic": "^1.1.0", 421 | "has": "^1.0.3", 422 | "side-channel": "^1.0.4" 423 | } 424 | }, 425 | "is-arguments": { 426 | "version": "1.1.1", 427 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 428 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 429 | "dev": true, 430 | "requires": { 431 | "call-bind": "^1.0.2", 432 | "has-tostringtag": "^1.0.0" 433 | } 434 | }, 435 | "is-bigint": { 436 | "version": "1.0.4", 437 | "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", 438 | "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", 439 | "dev": true, 440 | "requires": { 441 | "has-bigints": "^1.0.1" 442 | } 443 | }, 444 | "is-boolean-object": { 445 | "version": "1.1.2", 446 | "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", 447 | "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", 448 | "dev": true, 449 | "requires": { 450 | "call-bind": "^1.0.2", 451 | "has-tostringtag": "^1.0.0" 452 | } 453 | }, 454 | "is-callable": { 455 | "version": "1.2.4", 456 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", 457 | "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", 458 | "dev": true 459 | }, 460 | "is-date-object": { 461 | "version": "1.0.5", 462 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", 463 | "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", 464 | "dev": true, 465 | "requires": { 466 | "has-tostringtag": "^1.0.0" 467 | } 468 | }, 469 | "is-generator-function": { 470 | "version": "1.0.10", 471 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", 472 | "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", 473 | "dev": true, 474 | "requires": { 475 | "has-tostringtag": "^1.0.0" 476 | } 477 | }, 478 | "is-negative-zero": { 479 | "version": "2.0.2", 480 | "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", 481 | "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", 482 | "dev": true 483 | }, 484 | "is-number-object": { 485 | "version": "1.0.7", 486 | "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", 487 | "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", 488 | "dev": true, 489 | "requires": { 490 | "has-tostringtag": "^1.0.0" 491 | } 492 | }, 493 | "is-object": { 494 | "version": "1.0.2", 495 | "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", 496 | "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", 497 | "dev": true 498 | }, 499 | "is-regex": { 500 | "version": "1.1.4", 501 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", 502 | "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", 503 | "dev": true, 504 | "requires": { 505 | "call-bind": "^1.0.2", 506 | "has-tostringtag": "^1.0.0" 507 | } 508 | }, 509 | "is-shared-array-buffer": { 510 | "version": "1.0.2", 511 | "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", 512 | "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", 513 | "dev": true, 514 | "requires": { 515 | "call-bind": "^1.0.2" 516 | } 517 | }, 518 | "is-string": { 519 | "version": "1.0.7", 520 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", 521 | "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", 522 | "dev": true, 523 | "requires": { 524 | "has-tostringtag": "^1.0.0" 525 | } 526 | }, 527 | "is-symbol": { 528 | "version": "1.0.4", 529 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", 530 | "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", 531 | "dev": true, 532 | "requires": { 533 | "has-symbols": "^1.0.2" 534 | } 535 | }, 536 | "is-typed-array": { 537 | "version": "1.1.8", 538 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", 539 | "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", 540 | "dev": true, 541 | "requires": { 542 | "available-typed-arrays": "^1.0.5", 543 | "call-bind": "^1.0.2", 544 | "es-abstract": "^1.18.5", 545 | "foreach": "^2.0.5", 546 | "has-tostringtag": "^1.0.0" 547 | } 548 | }, 549 | "is-weakref": { 550 | "version": "1.0.2", 551 | "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", 552 | "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", 553 | "dev": true, 554 | "requires": { 555 | "call-bind": "^1.0.2" 556 | } 557 | }, 558 | "isarray": { 559 | "version": "0.0.1", 560 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 561 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 562 | "dev": true 563 | }, 564 | "jade": { 565 | "version": "0.26.3", 566 | "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", 567 | "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", 568 | "dev": true, 569 | "requires": { 570 | "commander": "0.6.1", 571 | "mkdirp": "0.3.0" 572 | }, 573 | "dependencies": { 574 | "commander": { 575 | "version": "0.6.1", 576 | "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 577 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", 578 | "dev": true 579 | }, 580 | "mkdirp": { 581 | "version": "0.3.0", 582 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", 583 | "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", 584 | "dev": true 585 | } 586 | } 587 | }, 588 | "jshint": { 589 | "version": "2.13.4", 590 | "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.4.tgz", 591 | "integrity": "sha512-HO3bosL84b2qWqI0q+kpT/OpRJwo0R4ivgmxaO848+bo10rc50SkPnrtwSFXttW0ym4np8jbJvLwk5NziB7jIw==", 592 | "dev": true, 593 | "requires": { 594 | "cli": "~1.0.0", 595 | "console-browserify": "1.1.x", 596 | "exit": "0.1.x", 597 | "htmlparser2": "3.8.x", 598 | "lodash": "~4.17.21", 599 | "minimatch": "~3.0.2", 600 | "strip-json-comments": "1.0.x" 601 | }, 602 | "dependencies": { 603 | "minimatch": { 604 | "version": "3.0.8", 605 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", 606 | "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", 607 | "dev": true, 608 | "requires": { 609 | "brace-expansion": "^1.1.7" 610 | } 611 | } 612 | } 613 | }, 614 | "lodash": { 615 | "version": "4.17.21", 616 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 617 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 618 | "dev": true 619 | }, 620 | "lolex": { 621 | "version": "1.3.2", 622 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", 623 | "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", 624 | "dev": true 625 | }, 626 | "lru-cache": { 627 | "version": "2.7.3", 628 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 629 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 630 | "dev": true 631 | }, 632 | "merge-descriptors": { 633 | "version": "1.0.1", 634 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 635 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", 636 | "dev": true 637 | }, 638 | "minimatch": { 639 | "version": "0.3.0", 640 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 641 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 642 | "dev": true, 643 | "requires": { 644 | "lru-cache": "2", 645 | "sigmund": "~1.0.0" 646 | } 647 | }, 648 | "minimist": { 649 | "version": "0.0.8", 650 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 651 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 652 | "dev": true 653 | }, 654 | "mkdirp": { 655 | "version": "0.5.1", 656 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 657 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 658 | "dev": true, 659 | "requires": { 660 | "minimist": "0.0.8" 661 | } 662 | }, 663 | "mocha": { 664 | "version": "2.5.3", 665 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", 666 | "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", 667 | "dev": true, 668 | "requires": { 669 | "commander": "2.3.0", 670 | "debug": "2.2.0", 671 | "diff": "1.4.0", 672 | "escape-string-regexp": "1.0.2", 673 | "glob": "3.2.11", 674 | "growl": "1.9.2", 675 | "jade": "0.26.3", 676 | "mkdirp": "0.5.1", 677 | "supports-color": "1.2.0", 678 | "to-iso-string": "0.0.2" 679 | } 680 | }, 681 | "module-not-found-error": { 682 | "version": "1.0.1", 683 | "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", 684 | "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", 685 | "dev": true 686 | }, 687 | "ms": { 688 | "version": "0.7.1", 689 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 690 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", 691 | "dev": true 692 | }, 693 | "object-inspect": { 694 | "version": "1.12.0", 695 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", 696 | "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", 697 | "dev": true 698 | }, 699 | "object-keys": { 700 | "version": "1.1.1", 701 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 702 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 703 | "dev": true 704 | }, 705 | "object.assign": { 706 | "version": "4.1.2", 707 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", 708 | "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", 709 | "dev": true, 710 | "requires": { 711 | "call-bind": "^1.0.0", 712 | "define-properties": "^1.1.3", 713 | "has-symbols": "^1.0.1", 714 | "object-keys": "^1.1.1" 715 | } 716 | }, 717 | "once": { 718 | "version": "1.4.0", 719 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 720 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 721 | "dev": true, 722 | "requires": { 723 | "wrappy": "1" 724 | } 725 | }, 726 | "path-is-absolute": { 727 | "version": "1.0.1", 728 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 729 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 730 | "dev": true 731 | }, 732 | "proxyquire": { 733 | "version": "1.8.0", 734 | "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", 735 | "integrity": "sha1-AtUUpb7ZhvBMuyCTrxZ0FTX3ntw=", 736 | "dev": true, 737 | "requires": { 738 | "fill-keys": "^1.0.2", 739 | "module-not-found-error": "^1.0.0", 740 | "resolve": "~1.1.7" 741 | } 742 | }, 743 | "readable-stream": { 744 | "version": "1.1.14", 745 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 746 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 747 | "dev": true, 748 | "requires": { 749 | "core-util-is": "~1.0.0", 750 | "inherits": "~2.0.1", 751 | "isarray": "0.0.1", 752 | "string_decoder": "~0.10.x" 753 | } 754 | }, 755 | "resolve": { 756 | "version": "1.1.7", 757 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 758 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 759 | "dev": true 760 | }, 761 | "safe-buffer": { 762 | "version": "5.2.1", 763 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 764 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 765 | "dev": true 766 | }, 767 | "samsam": { 768 | "version": "1.1.2", 769 | "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", 770 | "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", 771 | "dev": true 772 | }, 773 | "sax": { 774 | "version": "1.1.6", 775 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.6.tgz", 776 | "integrity": "sha1-XWFr6KXmB9VOEUr65Vt+ry/MMkA=" 777 | }, 778 | "side-channel": { 779 | "version": "1.0.4", 780 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 781 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 782 | "dev": true, 783 | "requires": { 784 | "call-bind": "^1.0.0", 785 | "get-intrinsic": "^1.0.2", 786 | "object-inspect": "^1.9.0" 787 | } 788 | }, 789 | "sigmund": { 790 | "version": "1.0.1", 791 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 792 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 793 | "dev": true 794 | }, 795 | "sinon": { 796 | "version": "1.17.7", 797 | "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", 798 | "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", 799 | "dev": true, 800 | "requires": { 801 | "formatio": "1.1.1", 802 | "lolex": "1.3.2", 803 | "samsam": "1.1.2", 804 | "util": ">=0.10.3 <1" 805 | } 806 | }, 807 | "string.prototype.trimend": { 808 | "version": "1.0.4", 809 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", 810 | "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", 811 | "dev": true, 812 | "requires": { 813 | "call-bind": "^1.0.2", 814 | "define-properties": "^1.1.3" 815 | } 816 | }, 817 | "string.prototype.trimstart": { 818 | "version": "1.0.4", 819 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", 820 | "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", 821 | "dev": true, 822 | "requires": { 823 | "call-bind": "^1.0.2", 824 | "define-properties": "^1.1.3" 825 | } 826 | }, 827 | "string_decoder": { 828 | "version": "0.10.31", 829 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 830 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 831 | "dev": true 832 | }, 833 | "strip-json-comments": { 834 | "version": "1.0.4", 835 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", 836 | "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", 837 | "dev": true 838 | }, 839 | "supports-color": { 840 | "version": "1.2.0", 841 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", 842 | "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", 843 | "dev": true 844 | }, 845 | "svgpath": { 846 | "version": "2.5.0", 847 | "resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.5.0.tgz", 848 | "integrity": "sha512-o/vohwqjUO9nDAh4rcjE3KaW/v//At8UJu2LJMybXidf5QLQLVA4bxH0//4YCsr+1H4Gw1Wi/Jc62ynzSBYidw==" 849 | }, 850 | "to-iso-string": { 851 | "version": "0.0.2", 852 | "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", 853 | "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", 854 | "dev": true 855 | }, 856 | "type-detect": { 857 | "version": "1.0.0", 858 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", 859 | "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", 860 | "dev": true 861 | }, 862 | "unbox-primitive": { 863 | "version": "1.0.1", 864 | "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", 865 | "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", 866 | "dev": true, 867 | "requires": { 868 | "function-bind": "^1.1.1", 869 | "has-bigints": "^1.0.1", 870 | "has-symbols": "^1.0.2", 871 | "which-boxed-primitive": "^1.0.2" 872 | } 873 | }, 874 | "util": { 875 | "version": "0.12.4", 876 | "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", 877 | "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", 878 | "dev": true, 879 | "requires": { 880 | "inherits": "^2.0.3", 881 | "is-arguments": "^1.0.4", 882 | "is-generator-function": "^1.0.7", 883 | "is-typed-array": "^1.1.3", 884 | "safe-buffer": "^5.1.2", 885 | "which-typed-array": "^1.1.2" 886 | } 887 | }, 888 | "which-boxed-primitive": { 889 | "version": "1.0.2", 890 | "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", 891 | "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", 892 | "dev": true, 893 | "requires": { 894 | "is-bigint": "^1.0.1", 895 | "is-boolean-object": "^1.1.0", 896 | "is-number-object": "^1.0.4", 897 | "is-string": "^1.0.5", 898 | "is-symbol": "^1.0.3" 899 | } 900 | }, 901 | "which-typed-array": { 902 | "version": "1.1.7", 903 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", 904 | "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", 905 | "dev": true, 906 | "requires": { 907 | "available-typed-arrays": "^1.0.5", 908 | "call-bind": "^1.0.2", 909 | "es-abstract": "^1.18.5", 910 | "foreach": "^2.0.5", 911 | "has-tostringtag": "^1.0.0", 912 | "is-typed-array": "^1.1.7" 913 | } 914 | }, 915 | "wrappy": { 916 | "version": "1.0.2", 917 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 918 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 919 | "dev": true 920 | }, 921 | "xmldoc": { 922 | "version": "0.5.1", 923 | "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-0.5.1.tgz", 924 | "integrity": "sha1-kuQ36QDb/wRFDvrpDTyl8WVl9zg=", 925 | "requires": { 926 | "sax": "~1.1.1" 927 | } 928 | } 929 | } 930 | } 931 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svg-flatten", 3 | "version": "1.0.1", 4 | "description": "Turns SVG shapes (polygon, polyline, rect, g) into SVG paths. It can merge groups and apply transforms.", 5 | "main": "src/lib.js", 6 | "dependencies": { 7 | "svgpath": "^2.1.6", 8 | "xmldoc": "^0.5.0" 9 | }, 10 | "devDependencies": { 11 | "chai": "^3.5.0", 12 | "jshint": "^2.9.1", 13 | "mocha": "^2.4.5", 14 | "proxyquire": "^1.7.9", 15 | "sinon": "^1.17.4" 16 | }, 17 | "scripts": { 18 | "test": "mocha", 19 | "lint": "jshint **/*.js" 20 | }, 21 | "keywords": [ 22 | "svg", 23 | "flatten", 24 | "flattener", 25 | "shape", 26 | "circle", 27 | "ellipse", 28 | "line", 29 | "path", 30 | "polygon", 31 | "polyline", 32 | "rect", 33 | "g", 34 | "transform" 35 | ], 36 | "author": "alex-pex", 37 | "license": "ISC", 38 | "repository": "stadline/svg-flatten" 39 | } 40 | -------------------------------------------------------------------------------- /src/flatten.js: -------------------------------------------------------------------------------- 1 | var transform = require('./transform.js'); 2 | var xmldoc = require('xmldoc'); 3 | 4 | function flattenSvg(dom) { 5 | var newChildren = []; 6 | 7 | dom.children.forEach(function (child) { 8 | newChildren.push(flatten(child)); 9 | }); 10 | 11 | dom.children = newChildren; 12 | 13 | if (newChildren.length > 0) { 14 | dom.firstChild = newChildren[0]; 15 | dom.lastChild = newChildren[newChildren.length - 1]; 16 | } 17 | 18 | return dom; 19 | } 20 | 21 | function flattenGroup(dom) { 22 | var path = new xmldoc.XmlDocument(''); 23 | 24 | path.attr = dom.attr; 25 | path.attr.d = ""; 26 | 27 | dom.children.forEach(function (child) { 28 | var flatChild = transform(flatten(child)); 29 | 30 | if (flatChild.attr.d) { 31 | var prefix = path.attr.d.length ? " " : ""; 32 | path.attr.d += prefix + flatChild.attr.d; 33 | } 34 | }); 35 | 36 | return path; 37 | } 38 | 39 | function flatten(dom) { 40 | if (dom.name === 'svg') { 41 | return flattenSvg(dom); 42 | } else if (dom.name === 'g') { 43 | return flattenGroup(dom); 44 | } else { 45 | return dom; 46 | } 47 | } 48 | 49 | module.exports = flatten; -------------------------------------------------------------------------------- /src/lib.js: -------------------------------------------------------------------------------- 1 | var parseFn = require('./parse.js'); 2 | var pathifyFn = require('./pathify.js'); 3 | var transformFn = require('./transform.js'); 4 | var flattenFn = require('./flatten.js'); 5 | 6 | function Wrapper(source) { 7 | if (typeof source === "string") { 8 | this._value = parseFn(source); 9 | } else { 10 | this._value = source; 11 | } 12 | 13 | this.pathify = function() { 14 | this._value = pathifyFn(this._value); 15 | return this; 16 | }; 17 | 18 | this.transform = function() { 19 | this._value = transformFn(this._value); 20 | return this; 21 | }; 22 | 23 | this.flatten = function() { 24 | this._value = flattenFn(this._value); 25 | return this; 26 | }; 27 | 28 | this.value = function() { 29 | if (typeof source === "string") { 30 | var meta = source.substr(0, source.indexOf("<" + this._value.name)); 31 | return meta + this._value.toString(); 32 | } else { 33 | return this._value; 34 | } 35 | }; 36 | } 37 | 38 | module.exports = function(source) { 39 | return new Wrapper(source); 40 | }; 41 | -------------------------------------------------------------------------------- /src/parse.js: -------------------------------------------------------------------------------- 1 | var xmldoc = require('xmldoc'); 2 | 3 | module.exports = function (source) { 4 | try { 5 | return new xmldoc.XmlDocument(source); 6 | } catch (exception) { 7 | var dom = new xmldoc.XmlDocument(''); 8 | dom.attr.reason = exception.toString(); 9 | 10 | return dom; 11 | } 12 | }; -------------------------------------------------------------------------------- /src/pathify.js: -------------------------------------------------------------------------------- 1 | /*jshint singleGroups: false*/ 2 | 3 | function _convertEllipse(cx = 0, cy = 0, rx = 0, ry = 0) { 4 | return "M" + (cx - rx) + "," + cy + "a" + rx + "," + ry + " 0 1,0 " + (rx * 2) + ",0a" + rx + "," + ry + " 0 1,0 " + (rx * -2) + ",0"; 5 | } 6 | 7 | function _convertPoints(points) { 8 | var path = ""; 9 | 10 | for (var i=0; i 0) { 28 | dom.firstChild = newChildren[0]; 29 | dom.lastChild = newChildren[newChildren.length - 1]; 30 | } 31 | 32 | return dom; 33 | } 34 | 35 | function convertCircle(dom) { 36 | var path = _convertEllipse(dom.attr.cx, dom.attr.cy, dom.attr.r, dom.attr.r); 37 | 38 | delete dom.attr.cx; 39 | delete dom.attr.cy; 40 | delete dom.attr.r; 41 | 42 | dom.name = 'path'; 43 | dom.attr.d = path; 44 | 45 | return dom; 46 | } 47 | 48 | function convertEllipse(dom) { 49 | var path = _convertEllipse(dom.attr.cx, dom.attr.cy, dom.attr.rx, dom.attr.ry); 50 | 51 | delete dom.attr.cx; 52 | delete dom.attr.cy; 53 | delete dom.attr.rx; 54 | delete dom.attr.ry; 55 | 56 | dom.name = 'path'; 57 | dom.attr.d = path; 58 | 59 | return dom; 60 | } 61 | 62 | function convertLine(dom) { 63 | var path = _convertPoints([dom.attr.x1, dom.attr.y1, dom.attr.x2, dom.attr.y2]); 64 | 65 | delete dom.attr.x1; 66 | delete dom.attr.y1; 67 | delete dom.attr.x2; 68 | delete dom.attr.y2; 69 | 70 | dom.name = 'path'; 71 | dom.attr.d = path; 72 | 73 | return dom; 74 | } 75 | 76 | function convertPolygon(dom) { 77 | var points = dom.attr.points.trim().split(/[\s,]+/); 78 | var path = _convertPoints(points) + "z"; 79 | 80 | delete dom.attr.points; 81 | 82 | dom.name = 'path'; 83 | dom.attr.d = path; 84 | 85 | return dom; 86 | } 87 | 88 | function convertPolyline(dom) { 89 | var points = dom.attr.points.trim().split(/[\s,]+/); 90 | var path = _convertPoints(points); 91 | 92 | delete dom.attr.points; 93 | 94 | dom.name = 'path'; 95 | dom.attr.d = path; 96 | 97 | return dom; 98 | } 99 | 100 | function convertRect(dom) { 101 | var x = parseFloat(dom.attr.x || 0); 102 | var y = parseFloat(dom.attr.y || 0); 103 | var width = parseFloat(dom.attr.width); 104 | var height = parseFloat(dom.attr.height); 105 | 106 | var points = []; 107 | points.push(x, y); 108 | points.push(x + width, y); 109 | points.push(x + width, y + height); 110 | points.push(x, y + height); 111 | var path = _convertPoints(points) + "z"; 112 | 113 | delete dom.attr.x; 114 | delete dom.attr.y; 115 | delete dom.attr.width; 116 | delete dom.attr.height; 117 | 118 | dom.name = 'path'; 119 | dom.attr.d = path; 120 | 121 | return dom; 122 | } 123 | 124 | function pathify(dom) { 125 | if (dom.name === 'svg') { 126 | return convertGroup(dom); 127 | } else if (dom.name === 'circle') { 128 | return convertCircle(dom); 129 | } else if (dom.name === 'ellipse') { 130 | return convertEllipse(dom); 131 | } else if (dom.name === 'line') { 132 | return convertLine(dom); 133 | } else if (dom.name === 'polygon') { 134 | return convertPolygon(dom); 135 | } else if (dom.name === 'polyline') { 136 | return convertPolyline(dom); 137 | } else if (dom.name === 'rect') { 138 | return convertRect(dom); 139 | } else if (dom.name === 'g') { 140 | return convertGroup(dom); 141 | } else { 142 | return dom; 143 | } 144 | } 145 | 146 | module.exports = pathify; 147 | -------------------------------------------------------------------------------- /src/transform.js: -------------------------------------------------------------------------------- 1 | var svgpath = require('svgpath'); 2 | 3 | function transformGroup(dom) { 4 | var newChildren = []; 5 | 6 | dom.children.forEach(function (child) { 7 | newChildren.push(transform(child)); 8 | }); 9 | 10 | dom.children = newChildren; 11 | 12 | if (newChildren.length > 0) { 13 | dom.firstChild = newChildren[0]; 14 | dom.lastChild = newChildren[newChildren.length - 1]; 15 | } 16 | 17 | return dom; 18 | } 19 | 20 | function transformPath(dom) { 21 | dom.attr.d = svgpath(dom.attr.d).transform(dom.attr.transform) 22 | .round(10) 23 | .toString(); 24 | 25 | delete dom.attr.transform; 26 | 27 | return dom; 28 | } 29 | 30 | function transform(dom) { 31 | if (dom.name === 'path' && dom.attr.transform) { 32 | return transformPath(dom); 33 | } else if (dom.name === 'svg' || dom.name === 'g') { 34 | return transformGroup(dom); 35 | } else { 36 | return dom; 37 | } 38 | } 39 | 40 | module.exports = transform; -------------------------------------------------------------------------------- /test/flatten.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint mocha: true*/ 2 | 3 | var expect = require('chai').expect; 4 | var xmldoc = require('xmldoc'); 5 | var flattenFn = require('../src/flatten.js'); 6 | 7 | // test 8 | describe('svg-flatten: flatten function', function() { 9 | it('should flatten path groups', function() { 10 | var source = new xmldoc.XmlDocument(''); 11 | var target = new xmldoc.XmlDocument(''); 12 | 13 | // test 14 | expect(flattenFn(source).toString()).to.be.equal(target.toString()); 15 | }); 16 | 17 | it('should flatten nested path groups', function() { 18 | var source = new xmldoc.XmlDocument(''); 19 | var target = new xmldoc.XmlDocument(''); 20 | 21 | // test 22 | expect(flattenFn(source).toString()).to.be.equal(target.toString()); 23 | }); 24 | 25 | it('should work with complex groups', function() { 26 | var source = new xmldoc.XmlDocument(''); 27 | var target = new xmldoc.XmlDocument(''); 28 | 29 | // test 30 | expect(flattenFn(source).toString()).to.be.equal(target.toString()); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/lib-samples.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint mocha: true*/ 2 | 3 | var expect = require('chai').expect; 4 | var fs = require('fs'); 5 | var svgflatten = require('../src/lib.js'); 6 | var xmldoc = require('xmldoc'); 7 | 8 | // test 9 | describe('svg-flatten: test samples', function () { 10 | var samples = ["sample1", "sample2", "sample3"]; 11 | 12 | samples.forEach(function(basename) { 13 | it('should give accurate results (' + basename + ')', function () { 14 | var sample = fs.readFileSync(__dirname + '/samples/' + basename + '.svg', 'utf8'); 15 | var expectedResult = fs.readFileSync(__dirname + '/samples/' + basename + '_result.svg', 'utf8'); 16 | 17 | // test with string 18 | var result = svgflatten(sample) 19 | .pathify() 20 | .flatten() 21 | .transform() 22 | .value(); 23 | 24 | expect(result).to.be.equal(expectedResult); 25 | 26 | // test with dom 27 | var sampleDom = new xmldoc.XmlDocument(sample); 28 | var expectedResultDom = new xmldoc.XmlDocument(expectedResult); 29 | 30 | var resultDom = svgflatten(sampleDom) 31 | .pathify() 32 | .flatten() 33 | .transform() 34 | .value(); 35 | 36 | expect(resultDom.toString()).to.be.equal(expectedResultDom.toString()); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/lib.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint mocha: true*/ 2 | /*jshint expr: true*/ 3 | /*jshint multistr: true*/ 4 | 5 | var expect = require('chai').expect; 6 | var sinon = require('sinon'); 7 | var proxyquire = require('proxyquire'); 8 | 9 | // sample file 10 | var file = ' \ 11 | \ 12 | \ 13 | \ 14 | \ 15 | '; 16 | 17 | // test 18 | describe('svg-flatten lib', function() { 19 | var parse; 20 | var pathify; 21 | var transform; 22 | var flatten; 23 | var lib; 24 | 25 | beforeEach(function () { 26 | parse = sinon.stub(); 27 | pathify = sinon.stub(); 28 | transform = sinon.stub(); 29 | flatten = sinon.stub(); 30 | 31 | parse.withArgs(file).returns(file); 32 | 33 | // inject stubs into library 34 | lib = proxyquire('../src/lib.js', { 35 | './parse.js': parse, 36 | './pathify.js': pathify, 37 | './transform.js': transform, 38 | './flatten.js': flatten 39 | }); 40 | }); 41 | 42 | it('should wrap the source', function() { 43 | var wrapper = lib(file); 44 | 45 | // test 46 | expect(wrapper).to.be.an('object'); 47 | expect(wrapper._value).to.be.equal(file); 48 | }); 49 | 50 | it('should apply the parse filter', function() { 51 | // init mocks 52 | var parsedFile = { 53 | parsed: true 54 | }; 55 | 56 | parse.withArgs(file).returns(parsedFile); 57 | 58 | // test 59 | expect(lib(file)._value).to.be.equal(parsedFile); 60 | expect(parse.calledOnce).to.be.true; 61 | }); 62 | 63 | it('should apply the pathify filter', function() { 64 | var wrapper = lib(file); 65 | 66 | // init mocks 67 | var pathifiedFile = { 68 | pathified: true 69 | }; 70 | 71 | pathify.withArgs(file).returns(pathifiedFile); 72 | 73 | // test 74 | expect(wrapper.pathify()._value).to.be.equal(pathifiedFile); 75 | expect(pathify.calledOnce).to.be.true; 76 | }); 77 | 78 | it('should apply the transform filter', function() { 79 | var wrapper = lib(file); 80 | 81 | // init mocks 82 | var transformedFile = { 83 | transformed: true 84 | }; 85 | 86 | transform.withArgs(file).returns(transformedFile); 87 | 88 | // test 89 | expect(wrapper.transform()._value).to.be.equal(transformedFile); 90 | expect(transform.calledOnce).to.be.true; 91 | }); 92 | 93 | it('should apply the flatten filter', function() { 94 | var wrapper = lib(file); 95 | 96 | // init mocks 97 | var flatFile = { 98 | flat: true 99 | }; 100 | 101 | flatten.withArgs(file).returns(flatFile); 102 | 103 | // test 104 | expect(wrapper.flatten()._value).to.be.equal(flatFile); 105 | expect(flatten.calledOnce).to.be.true; 106 | }); 107 | 108 | it('should chain filters', function() { 109 | var wrapper = lib(file); 110 | 111 | // init mocks 112 | var pathifiedFile = { 113 | pathified: true 114 | }; 115 | 116 | var flatFile = { 117 | flat: true 118 | }; 119 | 120 | pathify.withArgs(file).returns(pathifiedFile); 121 | flatten.withArgs(pathifiedFile).returns(flatFile); 122 | 123 | // test 124 | expect(wrapper.pathify().flatten()._value).to.be.equal(flatFile); 125 | expect(parse.calledOnce).to.be.true; 126 | expect(pathify.calledOnce).to.be.true; 127 | expect(flatten.calledOnce).to.be.true; 128 | }); 129 | }); 130 | -------------------------------------------------------------------------------- /test/parse.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint mocha: true*/ 2 | /*jshint expr: true*/ 3 | /*jshint multistr: true*/ 4 | 5 | var expect = require('chai').expect; 6 | var parseFn = require('../src/parse.js'); 7 | 8 | // sample files 9 | var file1 = ' \ 10 | \ 11 | \ 12 | \ 13 | \ 14 | '; 15 | 16 | var file2 = ' \ 17 | \ 18 | \ 19 | \ 20 | \ 23 | \ 24 | \ 25 | \ 26 | \ 27 | \ 28 | \ 29 | \ 30 | \ 31 | \ 32 | \ 33 | \ 34 | \ 35 | '; 36 | 37 | // test 38 | describe('svg-flatten: parse function', function() { 39 | it('should successfully parse a simple svg', function() { 40 | var dom = parseFn(file1); 41 | 42 | // test root node 43 | expect(dom.name).to.be.equal('svg'); 44 | expect(dom.attr.viewBox).to.be.equal('0 0 1920.7 1133.7'); 45 | 46 | // test child nodes 47 | expect(dom.children.length).to.be.equal(1); 48 | expect(dom.children[0].name).to.be.equal('rect'); 49 | }); 50 | 51 | it('should successfully parse a complex svg', function() { 52 | var dom = parseFn(file2); 53 | 54 | // test root node 55 | expect(dom.name).to.be.equal('svg'); 56 | expect(dom.attr.viewBox).to.be.equal('0 0 1920.7 1133.7'); 57 | 58 | // test child nodes 59 | expect(dom.children.length).to.be.equal(10); 60 | expect(dom.children[0].name).to.be.equal('style'); 61 | expect(dom.children[1].name).to.be.equal('rect'); 62 | expect(dom.children[7].attr.transform).to.be.equal('translate(0, 100)'); 63 | }); 64 | 65 | it('should not fail when the source is invalid', function() { 66 | var dom = parseFn("invalid input"); 67 | 68 | // test root node 69 | expect(dom.name).to.be.equal('invalid'); 70 | expect(dom.attr.reason).not.to.be.empty; 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/pathify.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint mocha: true*/ 2 | 3 | var expect = require('chai').expect; 4 | var xmldoc = require('xmldoc'); 5 | var pathifyFn = require('../src/pathify.js'); 6 | 7 | // test 8 | describe('svg-flatten: pathify function', function() { 9 | it('should convert circle', function() { 10 | var source = new xmldoc.XmlDocument(''); 11 | var target = new xmldoc.XmlDocument(''); 12 | 13 | // test 14 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 15 | }); 16 | 17 | it('should convert circle without center point', function() { 18 | var source = new xmldoc.XmlDocument(''); 19 | var target = new xmldoc.XmlDocument(''); 20 | 21 | // test 22 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 23 | }); 24 | 25 | it('should convert circle without radius', function() { 26 | var source = new xmldoc.XmlDocument(''); 27 | var target = new xmldoc.XmlDocument(''); 28 | 29 | // test 30 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 31 | }); 32 | 33 | it('should convert ellipse', function() { 34 | var source = new xmldoc.XmlDocument(''); 35 | var target = new xmldoc.XmlDocument(''); 36 | 37 | // test 38 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 39 | }); 40 | 41 | it('should convert line', function() { 42 | var source = new xmldoc.XmlDocument(''); 43 | var target = new xmldoc.XmlDocument(''); 44 | 45 | // test 46 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 47 | }); 48 | 49 | it('should convert polygons', function() { 50 | var source = new xmldoc.XmlDocument(''); 51 | var target = new xmldoc.XmlDocument(''); 52 | 53 | // test 54 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 55 | }); 56 | 57 | it('should convert polyline', function() { 58 | var source = new xmldoc.XmlDocument(''); 59 | var target = new xmldoc.XmlDocument(''); 60 | 61 | // test 62 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 63 | }); 64 | 65 | it('should convert polyline with extra whitespaces', function() { 66 | var source = new xmldoc.XmlDocument(''); 67 | var target = new xmldoc.XmlDocument(''); 68 | 69 | // test 70 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 71 | }); 72 | 73 | it('should convert rect', function() { 74 | var source = new xmldoc.XmlDocument(''); 75 | var target = new xmldoc.XmlDocument(''); 76 | 77 | // test 78 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 79 | }); 80 | 81 | it('should preserve groups', function() { 82 | var source = new xmldoc.XmlDocument(''); 83 | 84 | // test 85 | expect(pathifyFn(source)).to.be.equal(source); 86 | }); 87 | it('should preserve nested groups', function() { 88 | var source = new xmldoc.XmlDocument(''); 89 | var target = new xmldoc.XmlDocument(''); 90 | 91 | // test 92 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 93 | }); 94 | 95 | it('should should convert group children', function() { 96 | var source = new xmldoc.XmlDocument(''); 97 | var target = new xmldoc.XmlDocument(''); 98 | 99 | // test 100 | expect(pathifyFn(source).toString()).to.be.equal(target.toString()); 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /test/samples/sample1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/samples/sample1_result.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/samples/sample2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/samples/sample2_result.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/samples/sample3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /test/samples/sample3_result.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/transform.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint mocha: true*/ 2 | 3 | var expect = require('chai').expect; 4 | var xmldoc = require('xmldoc'); 5 | var transformFn = require('../src/transform.js'); 6 | 7 | // test 8 | describe('svg-flatten: transform function', function() { 9 | it('should apply translate transformation', function() { 10 | var source = new xmldoc.XmlDocument(''); 11 | var target = new xmldoc.XmlDocument(''); 12 | 13 | // test 14 | expect(transformFn(source).toString()).to.be.equal(target.toString()); 15 | }); 16 | 17 | it('should apply rotate transformation', function() { 18 | var source = new xmldoc.XmlDocument(''); 19 | var target = new xmldoc.XmlDocument(''); 20 | 21 | // test 22 | expect(transformFn(source).toString()).to.be.equal(target.toString()); 23 | }); 24 | 25 | it('should apply chained transformation', function() { 26 | var source = new xmldoc.XmlDocument(''); 27 | var target = new xmldoc.XmlDocument(''); 28 | 29 | // test 30 | expect(transformFn(source).toString()).to.be.equal(target.toString()); 31 | }); 32 | 33 | it('should work with complex paths', function() { 34 | var circle = new xmldoc.XmlDocument(''); 35 | var ellipse = new xmldoc.XmlDocument(''); 36 | var line = new xmldoc.XmlDocument(''); 37 | var polygon = new xmldoc.XmlDocument(''); 38 | var polyline = new xmldoc.XmlDocument(''); 39 | var rect = new xmldoc.XmlDocument(''); 40 | var shape = new xmldoc.XmlDocument(''); 41 | 42 | // test 43 | expect(transformFn(circle).toString()).to.be.equal(''); 44 | expect(transformFn(ellipse).toString()).to.be.equal(''); 45 | expect(transformFn(line).toString()).to.be.equal(''); 46 | expect(transformFn(polygon).toString()).to.be.equal(''); 47 | expect(transformFn(polyline).toString()).to.be.equal(''); 48 | expect(transformFn(rect).toString()).to.be.equal(''); 49 | expect(transformFn(shape).toString()).to.be.equal(''); 50 | }); 51 | }); 52 | --------------------------------------------------------------------------------