diff options
| author | ruki <waruqi@gmail.com> | 2018-11-08 00:38:48 +0800 |
|---|---|---|
| committer | ruki <waruqi@gmail.com> | 2018-11-07 21:53:09 +0800 |
| commit | 26105034da4fcce7ac883c899d781f016559310d (patch) | |
| tree | c459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/svgo | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/svgo')
115 files changed, 26185 insertions, 0 deletions
diff --git a/node_modules/svgo/.bin/svgo b/node_modules/svgo/.bin/svgo new file mode 120000 index 00000000..746740a5 --- /dev/null +++ b/node_modules/svgo/.bin/svgo @@ -0,0 +1 @@ +../bin/svgo
\ No newline at end of file diff --git a/node_modules/svgo/.npmignore b/node_modules/svgo/.npmignore new file mode 100644 index 00000000..aab1a69a --- /dev/null +++ b/node_modules/svgo/.npmignore @@ -0,0 +1,11 @@ +docs
+examples
+test
+lib-cov
+.editorconfig
+.jshintignore
+.jshintrc
+.travis.yml
+lcov.info
+logo.svg
+CHANGELOG.MD
diff --git a/node_modules/svgo/.svgo.yml b/node_modules/svgo/.svgo.yml new file mode 100644 index 00000000..a2b6e520 --- /dev/null +++ b/node_modules/svgo/.svgo.yml @@ -0,0 +1,68 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + + - removeDoctype + - removeXMLProcInst + - removeComments + - removeMetadata + - removeXMLNS + - removeEditorsNSData + - cleanupAttrs + - minifyStyles + - convertStyleToAttrs + - cleanupIDs + - removeRasterImages + - removeUselessDefs + - cleanupNumericValues + - cleanupListOfValues + - convertColors + - removeUnknownsAndDefaults + - removeNonInheritableGroupAttrs + - removeUselessStrokeAndFill + - removeViewBox + - cleanupEnableBackground + - removeHiddenElems + - removeEmptyText + - convertShapeToPath + - moveElemsAttrsToGroup + - moveGroupAttrsToElems + - collapseGroups + - convertPathData + - convertTransform + - removeEmptyAttrs + - removeEmptyContainers + - mergePaths + - removeUnusedNS + - transformsWithOnePath + - sortAttrs + - removeTitle + - removeDesc + - removeDimensions + - removeAttrs + - removeElementsByAttr + - addClassesToSVGElement + - removeStyleElement + - addAttributesToSVGElement + +# configure the indent (default 4 spaces) used by `--pretty` here: +# +# @see https://github.com/svg/svgo/blob/master/lib/svgo/js2svg.js#L6 for more config options +# +# js2svg: +# pretty: true +# indent: ' ' diff --git a/node_modules/svgo/CHANGELOG.md b/node_modules/svgo/CHANGELOG.md new file mode 100644 index 00000000..7a2084d7 --- /dev/null +++ b/node_modules/svgo/CHANGELOG.md @@ -0,0 +1,421 @@ +### [ [>](https://github.com/svg/svgo/tree/v0.7.2) ] 0.7.2 / 29.01.2017 +* Extended `currentColor` match conditions (string, rx, bool) (by @AlimovSV) +* Fixed removing `<animate>` in `<stop>`. +* Fixed removing same transform in inner element in `removeUnknownsAndDefaults`. +* Fixed collapsing groups with same non-inheritable attribue. +* Corrected removing of leading zero in case of exponential notation. + +### [ [>](https://github.com/svg/svgo/tree/v0.7.1) ] 0.7.1 / 27.09.2016 +* Reverted the requirement of Node.js to version 0.10. +* Added `addAttributesToSVGElement` to the default config to allow using it with `--enable` option. +* Added korean translation of “How it works” doc (by @primeiros). + +### [ [>](https://github.com/svg/svgo/tree/v0.7.0) ] 0.7.0 / 25.08.2016 +* Required Node.js version has increased to 0.12. +* New plugins: `removeElementsByAttr` (by IDs or classes) by @elidupuis, + `addAttributesToSVGElement` by @gjjones, + `removeXMLNS` (for SVG inlining) by @ricardobeat. +* Tests now correctly pass in Windows with CRLF line endings. Pretty print now accounts system line endings. +* Fixed bugs with collapsing groups with masks and transforms in `collapseGroups`. +* Fixed bugs with erroneous removing IDs in `cleanupIDs`. +* Improved attributes sorting in `sortAttrs` by @darktrojan. +* `addClassesToSVGElement` no more repeats classes (by @ricardobeat). + +### [ [>](https://github.com/svg/svgo/tree/v0.6.6) ] 0.6.6 / 25.04.2016 +* Corrected CSSO API usage + +### [ [>](https://github.com/svg/svgo/tree/v0.6.5) ] 0.6.5 / 25.04.2016 +* Extra content inserted by editors are now being removed within `<foreignObject>` as well thus fixing bug “Namespace prefix … is not defined“ after applying SVGO. +* Doctype with entities declartion is now also being removed since svgo correctly parses them starting from the version [0.6.2](https://github.com/svg/svgo/tree/v0.6.2). +* Corrected `moveGroupAttrsToElems` not to move attributes to `g` content if it's referenced (has an `id`). +* `collapseGroups` now don't collapse a group if it has an animated attribute (SMIL). + +### [ [>](https://github.com/svg/svgo/tree/v0.6.4) ] 0.6.4 / 05.04.2016 +* Fixed bug in “[convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js)” plugin with converting styling properties to non-existent attributes (which are normally removed later by `removeUnknownsAndDefaults`). +* Added `--indent` option to style pretty-printed SVG. (e.g. `--indent 2`) (by @scurker). +* Added `currentColor` param to `convertColors` plugin for converting values like `fill` and `stroke` to `currentColor` (by @scurker). +* Bumped CSSO to the current version and used [its new shiny API](https://github.com/css/csso#api) (thanks to @lahmatiy). + +### [ [>](https://github.com/svg/svgo/tree/v0.6.3) ] 0.6.3 / 20.03.2016 +* Smart rounding (introduced in 0.4.5) now applies only when rounding is needed, thus making subsequent passes more stable. +* Fixed regression in converting curves to arcs. +* `xlink:href` references are now being checked by local name `href`, thus correctly working with another namespace prefix. +* Fixed `id` removing with disabled `plugins/convertStyleToAttrs.js`. + +### [ [>](https://github.com/svg/svgo/tree/v0.6.2) ] 0.6.2 / 08.03.2016 +* Better error handling and messaging improvements. +* SVG files with XML entities (e.g. from Adobe Illustrator) are now correctly being parsed. +* Fixed error on converting curves to arcs. +* Corrected rounding in subsequent passes with `--multipass` option. +* Data URI option now handles charset (by @holymonson) +* Tranformations are no longer moved to group if there is a mask (`plugins/moveElemsAttrsToGroup.js`). +* Fixed matrix decomposition losing sign in case like `[1, 0, 0, -1, 0, 0]` (`scale(1 -1)`). +* Fixed crash on uppercased color name. +* Paths with `id` and without `stroke-width` aren't being trasformed now since `stroke-width` may be applied later. + +### [ [>](https://github.com/svg/svgo/tree/v0.6.1) ] 0.6.1 / 21.11.2015 +* Added option `--quiet` to suppress output (by @phihag). +* Removed `lib-cov` folder from the package, which was erroneously included before. +* Fixed errors in “[minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js)” when there are `<style>` elements with `CDATA` content or without content at all. +* Amended transform functions parsing to prevent errors when there are no separators between numbers (which isn't allowed by syntax, but understood by browsers). + +### [ [>](https://github.com/svg/svgo/tree/v0.6.0) ] 0.6.0 / 08.11.2015 +* New optimization: circular curves now being converted to arcs. A notable improvement for circles within paths. +* New plugin “[minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js)” which minifies `<style>` elments content with CSSO by @strarsis (svgo still doesn't understand its content) +* New plugin “[removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js)” (disabled by default) by @betsydupuis. +* Fixed issues wuth parsing numbers with exponent fraction (could happen with high precision >= 7). +* Fixed rounding error due to incorrect preserving of precision in transformations. +* Fixed shortand curve distortion due to converted previous curve to not a curve. +* Fixed interoperability issue with `precision` cli-option and `full` config. +* Fixed an error produced by “[removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js)” by @thiakil +* Another Inkscape prefix namespace is being removed. +* Fixed an issue in [moveElemsAttrsToGroup“](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup“.js)” with transforms moved around `clip-path`. + +### [ [>](https://github.com/svg/svgo/tree/v0.5.6) ] 0.5.6 / 13.08.2015 +* Fixed paths removing. + +### [ [>](https://github.com/svg/svgo/tree/v0.5.5) ] 0.5.5 / 05.08.2015 +* Reverted debugging changes. + +### [ [>](https://github.com/svg/svgo/tree/v0.5.4) ] 0.5.4 / 05.08.2015 +* New parameter `useShortTags` by @bradbarrow. Now svgo can produce correct non-selfclosing tags (useful in HTML in old browsers). +* Fixed failing on empty transformation (which could be produced by two opposite). +* Fixed removing paths which have numbers with exponent notation. +* Fixed a bug with arc transformation. +* Some typo fixes. + +### [ [>](https://github.com/svg/svgo/tree/v0.5.3) ] 0.5.3 / 21.06.2015 +* Fixed breaking related to rounding functions in “[convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js)”. +* Fixed a bug with ID in animations not being worked on by “[cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js)”. +* Fixed a bug with quoted reference in `url()`. +* Now, if there are several same IDs in the document, then the first one is used and others are being removed. +* New command-line option `--show-plugins` displaying list of plugins. +* Two new optional plugins: “[removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js)” (removes `width` and `height` if there is `viewBox`) and “[removeAttrsPlugin](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js)” (by @bennyschudel). + +### [ [>](https://github.com/svg/svgo/tree/v0.5.2) ] 0.5.2 / 24.05.2015 +* Introduced new `transformPrecision` option for better image quality (defaults to 5) in “[convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js)” and “[convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js)” (for the purpose of applying transformations) plugins. +* Matrix transformations now can be decomposed into a combination of few simple transforms like `translate`, `rotate`, `scale`. +* Arcs (paths `arcto` command) are now correctly being transformed into another arcs without being converting to Bezier curves. +* Fixed an issue with “[mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js)” failing to detect paths intersection in some cases. +* Fixed a bug with “[removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js)” removing some paths, which was introduced in [v0.5.1](https://github.com/svg/svgo/tree/v0.5.1). +* Fixed a bug with transformation having `rotate()` with optional parameters. +* Patterns with inherited attributes are no longer being removed. +* Styles are no longer being removed from `<desc>` (by @dennari). +* SVGO no longer breaks during parsing. +* Added `clone()` method to JSAPI (by @jakearchibald) + +### [ [>](https://github.com/svg/svgo/tree/v0.5.1) ] 0.5.1 / 30.03.2015 +* added new command-line option to set precision in floating point numbers. +* fixed all known image-disruptive bugs +* Notably [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) plugin now checks for possible intersections to avoid side-effects +* new plugin [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) to remove elements in ``<defs>`` and similar non-rendering elements without an ``id`` and thus cannot be used +* fix for ``--multipass`` command line option (by @dfilatov) +* improved [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) and [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) plugins (by @YetiOr) +* new plugin for image manipulation [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) (by @kiyopikko) +* fixed fail on comments after closing root ``</svg>`` tag +* updated parsing to account meaningful spaces in ``<text>`` +* ``data-*`` attributes are now preserved in [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) +* prevented plugins from failing in ``<foreignObject>`` +* [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) plugin now converts other units to pixels (if it's better) +* [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) plugin is enabled again with correct work in case of inherited attributes +* fixed fail on images with incorrect paths like ``<path d="z"/>`` +* svgo now understands if an input is a folder (remember, you can set output to folder as well) +* added support for some properties from SVG 2 like ``vector-effect="non-scaling-stroke"`` +* removed option to remove an ``id`` on root ``<svg>`` tag in [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) since it's already being done in [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) + +### [ [>](https://github.com/svg/svgo/tree/v0.5.0) ] 0.5.0 / 05.11.2014 +* added ``--multipass`` command line option which repeatedly applies optimizations like collapsing groups (by @dfilatov) +* exposed JSAPI as a factory method (by @mistakster) +* added removeDesc plugin (by @dwabyick), disabled by default +* [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) plugin is disabled by default since it's unable to check inherited properties +* transformations now apply to paths with arcs in [plugins/convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) +* a lot of bug fixes mostly related to transformations + +### [ [>](https://github.com/svg/svgo/tree/v0.4.5) ] 0.4.5 / 02.08.2014 +* significally improved plugin [plugins/convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js): + - Now data is being written relative or absolute whichever is shorter. You can turn it off by setting ``utilizeAbsolute`` to ``false``. + - Smarter rounding: values like 2.499 now rounds to 2.5. Rounding now takes in account accumulutive error meaning that points will not be misplaced due to rounding more than it neccessary. + - Fixed couple bugs. +* ``--output`` option now can be a folder along with ``--folder``, thanks to @mako-taco. +* [plugins/cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) now have ``prefix`` option in case you want to combine multiple svg later (by @DanielMazurkiewicz). +* Quotes now being escaped in attributes (by @ditesh). +* Minor bugfixes. + +### [ [>](https://github.com/svg/svgo/tree/v0.4.4) ] 0.4.4 / 14.01.2014 +* new plugin [plugins/removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) (disabled by default, close [#159](https://github.com/svg/svgo/issues/159)) +* plugins/convertPathData: skip data concatenation for z instruction in collapseRepeated +* plugins/removeUnknownsAndDefaults: do not remove overriden attributes with default values (fix [#161](https://github.com/svg/svgo/issues/161) and [#168](https://github.com/svg/svgo/issues/168)) +* plugins/removeViewBox: disable by default (fix [#139](https://github.com/svg/svgo/issues/139)) +* update README with [gulp task](https://github.com/ben-eb/gulp-svgmin) + +### [ [>](https://github.com/svg/svgo/tree/v0.4.3) ] 0.4.3 / 02.01.2014 +* new plugin [plugins/convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) (close [#96](https://github.com/svg/svgo/issues/96)) +* update sax version to fix [#140](https://github.com/svg/svgo/issues/140) +* update deps + +### [ [>](https://github.com/svg/svgo/tree/v0.4.2) ] 0.4.2 / 19.12.2013 +* add `lcov.info` to npmignore +* fix `js-yaml` version to suppress deprecation warning in stdout + +### [ [>](https://github.com/svg/svgo/tree/v0.4.1) ] 0.4.1 / 18.11.2013 +* node >=0.8.0 + +### [ [>](https://github.com/svg/svgo/tree/v0.4.0) ] 0.4.0 / 18.11.2013 +* merge almost all pull-requests +* update dependencies + +### [ [>](https://github.com/svg/svgo/tree/v0.3.7) ] 0.3.7 / 24.06.2013 +* do not remove `result` attribute from filter primitives (fix [#122](https://github.com/svg/svgo/issues/122)) +* plugins/cleanupAttrs: replace newline with space when needed (fix [#119](https://github.com/svg/svgo/issues/119)) +* lib/coa: look for config file in current folder +* lib/coa: always traverse all files in the given folder +* deprecate svgo-grunt in favor of [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin) +* re-enable node-coveralls + +### [ [>](https://github.com/svg/svgo/tree/v0.3.6) ] 0.3.6 / 06.06.2013 +* plugins/removeNonInheritableGroupAttrs: more attrs groups to exclude (fix [#116](https://github.com/svg/svgo/issues/116) & [#118](https://github.com/svg/svgo/issues/118)) +* lib/coa: optimize folder file by file (temp fix [#114](https://github.com/svg/svgo/issues/114)) +* `.jshintrc`: JSHint 2.0 +* temporarily disable node-coveralls + +### [ [>](https://github.com/svg/svgo/tree/v0.3.5) ] 0.3.5 / 07.05.2013 +* plugins/transformsWithOnePath: fix curves bounding box calculation +* plugins/transformsWithOnePath: fix possible c+t or q+s bug + + +### [ [>](https://github.com/svg/svgo/tree/v0.3.4) ] 0.3.4 / 06.05.2013 +* plugins/convertPathData: fix m->M bug in some cases +* plugins/transformsWithOnePath: fix last point calculation for C/S/Q/T +* plugins/mergePaths: add space delimiter between z and m + +### [ [>](https://github.com/svg/svgo/tree/v0.3.3) ] 0.3.3 / 05.05.2013 +* plugins/convertPathData: convert very first m to M, fix applyTransforms with translate() (fix [#112](https://github.com/svg/svgo/issues/112)) +* plugins/transformsWithOnePath: fix real width/height rounding; fix scale transform origin; reorder transforms +* plugins/transformsWithOnePath: ability to set new width or height independently with auto rescaling + +### [ [>](https://github.com/svg/svgo/tree/v0.3.2) ] 0.3.2 / 03.05.2013 +* new plugin [plugins/sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) +* plugins/transformsWithOnePath: buggy hcrop (fix [#111](https://github.com/svg/svgo/issues/111)) +* Impossible to set output presision to 0 (no fractional part) (fix [#110](https://github.com/svg/svgo/issues/110)) +* Istanbul + coveralls.io +* update README with NPM version from badge.fury.io +* update README with dependency status from gemnasium.com +* npmignore unneeded files +* reoptimized project logo + +### [ [>](https://github.com/svg/svgo/tree/v0.3.1) ] 0.3.1 / 15.04.2013 +* plugins/transformsWithOnePath: resize SVG and automatically rescale inner Path +* better errors handling + +### [ [>](https://github.com/svg/svgo/tree/v0.3.0) ] 0.3.0 / 12.04.2013 +* global refactoring: getting rid of the many dependencies +* new plugin [plugins/mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) +* new plugin [plugins/transformsWithOnePath](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) (renamed and featured `cropAndCenterAlongPath`) +* config: replace default config with `full: true` +* coa: JSON string as value of `--config` +* coa: different types of Data URI strings (close [#105](https://github.com/svg/svgo/issues/105)) +* plugins/_transforms: allow spaces at the beginning of transform +* Travis CI: Nodejs 0.10 & 0.11 +* `node.extend` → `whet.extend` +* update `.gitignore` +* update docs + +### [ [>](https://github.com/svg/svgo/tree/v0.2.4) ] 0.2.4 / 05.04.2013 +* new plugin [plugins/cropAndCenterAlongPath](https://github.com/svg/svgo/blob/master/plugins/cropAndCenterAlongPath.js) for the [Fontello](https://github.com/fontello) project + +### [ [>](https://github.com/svg/svgo/tree/v0.2.3) ] 0.2.3 / 22.02.2013 +* new plugin [plugins/removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) (fix [#101](https://github.com/svg/svgo/issues/101)) +* new plugin [plugins/removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) (close [#98](https://github.com/svg/svgo/issues/98)) +* plugins/convertTransform: bug with trailing spaces in transform value string (fix [#103](https://github.com/svg/svgo/issues/103)) + +### [ [>](https://github.com/svg/svgo/tree/v0.2.2) ] 0.2.2 / 09.02.2013 +* plugins/convertTransforms: wrong translate() shorthand (fix [#94](https://github.com/svg/svgo/issues/94)) +* [yaml.js](https://github.com/jeremyfa/yaml.js) → [js-yaml](https://github.com/nodeca/js-yaml) +* update outdated deps + +### [ [>](https://github.com/svg/svgo/tree/v0.2.1) ] 0.2.1 / 18.01.2013 +* plugins/moveElemsAttrsToGroup + plugins/moveGroupAttrsToElems: move or just leave transform attr from Group to the inner Path Elems (close [#86](https://github.com/svg/svgo/issues/86)) +* plugins/removeViewBox: doesn't catch floating-point numbers (fix [#88](https://github.com/svg/svgo/issues/88)) +* plugins/cleanupEnableBackground: doesn't catch floating-point numbers (fix [#89](https://github.com/svg/svgo/issues/89)) +* plugins/cleanupNumericValues: wrong floating-point numbers regexp (fix [#92](https://github.com/svg/svgo/issues/92)) +* SVG file generated by fontcustom.com not properly compressed (fix [#90](https://github.com/svg/svgo/issues/90)) +* `README.ru.md`: стилизация русского языка, улучшение языковых конструкций, правка ошибок (close [#91](https://github.com/svg/svgo/issues/91)) +* minor JSHint warning fix + +### [ [>](https://github.com/svg/svgo/tree/v0.2.0) ] 0.2.0 / 23.12.2012 +* plugins/convertPathData: apply transforms to Path pata (close [#33](https://github.com/svg/svgo/issues/33)) +* plugins/convertPathData: `-1.816-9.278.682-13.604` parsing error (fix [#85](https://github.com/svg/svgo/issues/85)) +* plugins/convertTransform: `translate(10, 0)` eq `translate(10)`, but not `translate(10, 10)` eq `translate(10)` (fix [#83](https://github.com/svg/svgo/issues/83)) +* run plugins/cleanupIDs before plugins/collapseGroups (fix [#84](https://github.com/svg/svgo/issues/84)) +* update `.gitignore` + +### [ [>](https://github.com/svg/svgo/tree/v0.1.9) ] 0.1.9 / 17.12.2012 +* plugins/cleanupIDs: renamed from removeUnusedIDs; minify used IDs (fix [#7](https://github.com/svg/svgo/issues/7)) +* lib/svgo/js2svg: restore HTML entities back (fix [#80](https://github.com/svg/svgo/issues/80) + [#81](https://github.com/svg/svgo/issues/81)) +* plugins/removeDoctype: do not remove if custom XML entities presents (fix [#77](https://github.com/svg/svgo/issues/77)) +* lib/svgo/coa: refactoring, colors and fix [#70](https://github.com/svg/svgo/issues/70) +* lib/svgo: store elapsed time in result object +* usage examples with SVGZ (close [#18](https://github.com/svg/svgo/issues/18)) +* more optimized logo +* update `.gitignore` + +### [ [>](https://github.com/svg/svgo/tree/v0.1.8) ] 0.1.8 / 11.12.2012 +* new plugin [plugins/removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) (close [#75](https://github.com/svg/svgo/issues/75)) +* new plugin [plugins/removeUnusedIDs](https://github.com/svg/svgo/blob/master/plugins/removeUnusedIDs.js) (close [#76](https://github.com/svg/svgo/issues/76)) +* plugins/convertPathData: wrong M interpretation in some cases (fix [#73](https://github.com/svg/svgo/issues/73)) +* plugins/cleanupAttrs: use `isElem()` API +* `.travis.yml`: check all branches + + +### [ [>](https://github.com/svg/svgo/tree/v0.1.7) ] 0.1.7 / 08.12.2012 +* plugins/convertPathData: incorrect interpretation of `z + m` (fix [#69](https://github.com/svg/svgo/issues/69)) +* plugins/convertTransform: do a more accurate floating numbers rounding in `matrixToTransform()` (fix [#68](https://github.com/svg/svgo/issues/68)) + +### [ [>](https://github.com/svg/svgo/tree/v0.1.6) ] 0.1.6 / 07.12.2012 +* plugins/convertPathData: collapse repeated instructions only after curveSmoothShorthands (fix [#64](https://github.com/svg/svgo/issues/64)) +* lib/svgo/coa: handle 'there is nothing to optimize' case and display a message about it (fix [#61](https://github.com/svg/svgo/issues/61)) +* plugins/cleanupSVGElem: delete as useless artefact + + +### [ [>](https://github.com/svg/svgo/tree/v0.1.5) ] 0.1.5 / 06.12.2012 +* E-notated numbers in paths not recognised (fix [#63](https://github.com/svg/svgo/issues/63)) +* update README with `svgo-grunt` and `svgo-osx-folder-action` +* fix `mocha-as-promised` plug in node 0.6 + +### [ [>](https://github.com/svg/svgo/tree/v0.1.4) ] 0.1.4 / 05.12.2012 +* plugins/_collections: more defaults +* `README.ru.md` +* `docs/how-it-works/ru.md` +* mocha + mocha-as-promised + chai + chai-as-promised + should + istanbul = <3 +* update dependencies semvers in `package.json` +* `v0.1.x` and `v0.2.x` milestones + +### [ [>](https://github.com/svg/svgo/tree/v0.1.3) ] 0.1.3 / 30.11.2012 +* new plugin [plugins/cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) (close [#8](https://github.com/svg/svgo/issues/8)) +* plugins/removeDefaultPx functionality now included in plugins/removeUnknownsAndDefaults +* plugins/removeUnknownsAndDefaults: refactoring and picking up the complete elems+attrs collection (close [#59](https://github.com/svg/svgo/issues/59)) +* plugins/convertTransform: error in matrices multiplication (fix [#58](https://github.com/svg/svgo/issues/58)) +* plugins/convertTransform: mark translate() and scale() as useless only with one param (fix [#57](https://github.com/svg/svgo/issues/57)) +* plugins/convertPathData: drastic speed improvement with huge Path data +* plugins/convertPathData: fix the very first Mm with multiple points (fix [#56](https://github.com/svg/svgo/issues/56)) +* plugins/moveElemsAttrsToGroup: additional check for transform attr +* brand-new project `logo.svg` +* `.travis.yml`: build only master branch +* global `'use strict'` +* `.jshintignore` +* README and CHANGELOG: minor corrections + +### [ [>](https://github.com/svg/svgo/tree/v0.1.2) ] 0.1.2 / 24.11.2012 +* lib/svgo/svg2js: correct 'onerror' failure (fix [#51](https://github.com/svg/svgo/issues/51)) +* config: disable sax-js position tracking by default (fix [#52](https://github.com/svg/svgo/issues/52)) +* lib/svgo: rename 'startBytes' to 'inBytes' and 'endBytes' to 'outBytes' (close [#53](https://github.com/svg/svgo/issues/53)) +* plugins/removeUnknownsAndDefaults: remove SVG id attr (close [#54](https://github.com/svg/svgo/issues/54)) + +### [ [>](https://github.com/svg/svgo/tree/v0.1.1) ] 0.1.1 / 23.11.2012 +* plugins/moveElemsAttrsToGroup: fix inheitable only attrs array (fix [#47](https://github.com/svg/svgo/issues/47)) +* plugins/removeEmptyContainers: do not remove an empty 'svg' element (fix [#48](https://github.com/svg/svgo/issues/48)) +* plugins/removeDefaultPx: should also understand a floating-numbers too (fix [#49](https://github.com/svg/svgo/issues/49)) +* plugins/removeUnknownsAndDefaults: merge multiple groupDefaults attrs (close [#50](https://github.com/svg/svgo/issues/50)) + +### [ [>](https://github.com/svg/svgo/tree/v0.1.0) ] 0.1.0 / 22.11.2012 +* new plugin [plugins/removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) (close [#6](https://github.com/svg/svgo/issues/6)) +* plugins/convertPathData: convert straight curves into lines segments (close [#17](https://github.com/svg/svgo/issues/17)); remove an absolute coords conversions +* plugins/convertPathData: convert quadratic Bézier curveto into smooth shorthand (close [#31](https://github.com/svg/svgo/issues/31)) +* plugins/convertPathData: convert curveto into smooth shorthand (close [#30](https://github.com/svg/svgo/issues/30)) +* lib/svgo: global API refactoring (close [#37](https://github.com/svg/svgo/issues/37)) +* lib/svgo: fatal and stupid error in stream chunks concatenation (fix [#40](https://github.com/svg/svgo/issues/40)) +* lib/coa: batch folder optimization (close [#29](https://github.com/svg/svgo/issues/29)) +* lib/coa: support arguments as aliases to `--input` and `--output` (close [#28](https://github.com/svg/svgo/issues/28)) +* project logo by [Egor Bolhshakov](http://xizzzy.ru/) +* move modules to `./lib/svgo/` +* rename and convert `config.json` to `.svgo.yml` +* add [./docs/](https://github.com/svg/svgo/tree/master/docs) +* plugins/convertPathData: don't remove first `M` even if it's `0,0` +* plugins/convertPathData: stronger defense from infinite loop +* plugins/moveElemsAttrsToGroup: should affect only inheritable attributes (fix [#46](https://github.com/svg/svgo/issues/46))* +* plugins/removeComments: ignore comments which starts with '!' (close [#43](https://github.com/svg/svgo/issues/43)) +* config: `cleanupAttrs` should be before `convertStyleToAttrs` (fix [#44](https://github.com/svg/svgo/issues/44))* +* lib/svgo/jsAPI: add `eachAttr()` optional context param +* temporarily remove PhantomJS and `--test` (close [#38](https://github.com/svg/svgo/issues/38)) +* q@0.8.10 compatibility: 'end is deprecated, use done instead' fix +* add [Istanbul](https://github.com/gotwarlost/istanbul) code coverage +* update dependencies versions and gitignore +* README: add TODO section with versions milestones +* update README with License section +* update LICENSE with russian translation +* `.editorconfig`: 2 spaces for YAML + +### [ [>](https://github.com/svg/svgo/tree/v0.0.9) ] 0.0.9 / 29.10.2012 +* [plugins how-to](https://github.com/svg/svgo/tree/master/plugins#readme) (close [#27](https://github.com/svg/svgo/issues/27)) +* allow any plugin of any type to go in any order (close [#14](https://github.com/svg/svgo/issues/14)) +* allow to do a multiple optimizations with one init (close [#25](https://github.com/svg/svgo/issues/25)) +* plugins/convertPathData: global refactoring +* plugins/convertPathData: do all the tricks with absolute coords too (fix [#22](https://github.com/svg/svgo/issues/22)) +* plugins/convertPathData: accumulation of rounding errors (fix [#23](https://github.com/svg/svgo/issues/23)) +* plugins/convertPathData: prevent an infinity loop on invalid path data (fix [#26](https://github.com/svg/svgo/issues/26)) +* plugins/convertPathData: do not remove very first M from the path data (fix [#24](https://github.com/svg/svgo/issues/24)) +* plugins/convertPathData: optimize path data in <glyph> and <missing-glyph> (close [#20](https://github.com/svg/svgo/issues/20)) +* plugins/convertTransform: add patternTransform attribute to the process (close [#15](https://github.com/svg/svgo/issues/15)) +* plugins/convertTransform: Firefox: removing extra space in front of negative number is alowed only in path data, but not in transform (fix [#12](https://github.com/svg/svgo/issues/12)) +* plugins/removeXMLProcInst: remove only 'xml' but not 'xml-stylesheet' (fix [#21](https://github.com/svg/svgo/issues/15)) +* plugins/collapseGroups: merge split-level transforms (fix [#13](https://github.com/svg/svgo/issues/13)) +* jsdoc corrections + +### [ [>](https://github.com/svg/svgo/tree/v0.0.8) ] 0.0.8 / 20.10.2012 +* new plugin [convertTransform](plugins/convertTransform.js) (close [#5](https://github.com/svg/svgo/issues/5)) +* new plugin [removeUnusedNS](plugins/removeUnusedNS.js) +* plugins/convertPathData: remove useless segments +* plugins/convertPathData: a lot of refactoring +* plugins/convertPathData: round numbers before conditions because of exponential notation (fix [#3](https://github.com/svg/svgo/issues/3)) +* plugins/moveElemsAttrsToGroup: merge split-level transforms instead of replacing (fix [#10](https://github.com/svg/svgo/issues/10)) +* lib/svg2js: catch and output xml parser errors (fix [#4](https://github.com/svg/svgo/issues/4)) +* lib/coa: open file for writing only when we are ready (fix [#2](https://github.com/svg/svgo/issues/2)) +* lib/tools: node.extend module +* lib/plugins: refactoring +* lib/js2svg: refactoring +* lib/jsAPI: simplification and refactoring +* absolute urls in README +* update .editorconfig +* update .travis.yml with nodejs 0.9 + +### [ [>](https://github.com/svg/svgo/tree/v0.0.7) ] 0.0.7 / 14.10.2012 +* new plugin [convertPathData](plugins/convertPathData.js) +* --input data now can be a Data URI base64 string +* --output data now can be a Data URI base64 string with --datauri flag +* Travis CI +* JSHint corrections + .jshintrc +* [.editorconfig](http://editorconfig.org/) +* display time spent on optimization +* .svgo → config.json +* lib/phantom_wrapper.js → lib/phantom.js + +### [ [>](https://github.com/svg/svgo/tree/v0.0.6) ] 0.0.6 / 04.10.2012 +* add --test option to make a visual comparison of two files (PhantomJS pre-required) +* update README and CHANGELOG with the correct relative urls + +### [ [>](https://github.com/svg/svgo/tree/v0.0.5) ] 0.0.5 / 03.10.2012 +* every plugin now has [at least one test](plugins) +* removeViewBox, cleanupEnableBackground, removeEditorsNSData, convertStyleToAttrs and collapseGroups plugins fixes +* new --pretty option for the pretty printed SVG +* lib/config refactoring + +### [ [>](https://github.com/svg/svgo/tree/v0.0.4) ] 0.0.4 / 30.09.2012 +* new plugin [removeViewBox](plugins/removeViewBox.js) +* new plugin [cleanupEnableBackground](plugins/cleanupEnableBackground.js) +* display useful info after successful optimization +* 'npm test' with 'spec' mocha output by default + +### [ [>](https://github.com/svg/svgo/tree/v0.0.3) ] 0.0.3 / 29.09.2012 +* plugins/collapseGroups bugfix +* plugins/moveElemsAttrsToGroup bugfix +* svgo now display --help if running w/o arguments +* massive jsdoc updates +* plugins engine main filter function optimization + +### [ [>](https://github.com/svg/svgo/tree/v0.0.2) ] 0.0.2 / 28.09.2012 +* add --disable and --enable command line options +* add an empty values rejecting to coa.js +* update README + +### [ [>](https://github.com/svg/svgo/tree/v0.0.1) ] 0.0.1 / 27.09.2012 +* initial public version diff --git a/node_modules/svgo/LICENSE b/node_modules/svgo/LICENSE new file mode 100644 index 00000000..cd8d5003 --- /dev/null +++ b/node_modules/svgo/LICENSE @@ -0,0 +1,55 @@ +The MIT License + +Copyright © 2012–2016 Kir Belevich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Лицензия MIT + +Copyright © 2012–2016 Кир Белевич + +Данная лицензия разрешает лицам, получившим копию данного +программного обеспечения и сопутствующей документации +(в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно +использовать Программное Обеспечение без ограничений, включая +неограниченное право на использование, копирование, изменение, +добавление, публикацию, распространение, сублицензирование +и/или продажу копий Программного Обеспечения, также как и лицам, +которым предоставляется данное Программное Обеспечение, +при соблюдении следующих условий: + +Указанное выше уведомление об авторском праве и данные условия +должны быть включены во все копии или значимые части данного +Программного Обеспечения. + +ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», +БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, +ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, +СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ +ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ +ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ +ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, +ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ +ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ +ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. diff --git a/node_modules/svgo/Makefile b/node_modules/svgo/Makefile new file mode 100644 index 00000000..c11daab9 --- /dev/null +++ b/node_modules/svgo/Makefile @@ -0,0 +1,21 @@ +test: + @npm run test + +lib-cov: + @./node_modules/.bin/istanbul instrument --output lib-cov --no-compact --variable global.__coverage__ lib + +coverage: lib-cov + @COVERAGE=1 ISTANBUL_REPORTERS=text-summary ./node_modules/.bin/mocha --reporter mocha-istanbul + @rm -rf lib-cov + +coveralls: lib-cov + @COVERAGE=1 ISTANBUL_REPORTERS=lcovonly ./node_modules/.bin/mocha --reporter mocha-istanbul + @cat lcov.info | ./node_modules/.bin/coveralls + @rm -rf lib-cov lcov.info + +travis: jshint test coveralls + +jshint: + @npm run jshint + +.PHONY: test diff --git a/node_modules/svgo/README.md b/node_modules/svgo/README.md new file mode 100644 index 00000000..c77c6812 --- /dev/null +++ b/node_modules/svgo/README.md @@ -0,0 +1,155 @@ +**english** | [русский](https://github.com/svg/svgo/blob/master/README.ru.md) +- - - + +<img src="https://svg.github.io/svgo-logo.svg" width="200" height="200" alt="logo"/> + +## SVGO [](https://npmjs.org/package/svgo) [](https://gemnasium.com/svg/svgo) [](https://travis-ci.org/svg/svgo) [](https://coveralls.io/r/svg/svgo?branch=master) + +**SVG O**ptimizer is a Nodejs-based tool for optimizing SVG vector graphics files. + + +## Why? + +SVG files, especially exported from various editors, usually contain a lot of redundant and useless information such as editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting SVG rendering result. + +## What it can do + +SVGO has a plugin-based architecture, so almost every optimization is a separate plugin. + +Today we have: + +| Plugin | Description | +| ------ | ----------- | +| [cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) | cleanup attributes from newlines, trailing, and repeating spaces | +| [removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) | remove doctype declaration | +| [removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) | remove XML processing instructions | +| [removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) | remove comments | +| [removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) | remove `<metadata>` | +| [removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) | remove `<title>` (disabled by default) | +| [removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) | remove `<desc>` (only non-meaningful by default) | +| [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) | remove elements of `<defs>` without `id` | +| [removeXMLNS](https://github.com/svg/svgo/blob/master/plugins/removeXMLNS.js) | removes `xmlns` attribute (for inline svg, disabled by default) | +| [removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) | remove editors namespaces, elements, and attributes | +| [removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) | remove empty attributes | +| [removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) | remove hidden elements | +| [removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) | remove empty Text elements | +| [removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) | remove empty Container elements | +| [removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) | remove `viewBox` attribute when possible (disabled by default) | +| [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) | remove or cleanup `enable-background` attribute when possible | +| [minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js) | minify `<style>` elements content with [CSSO](https://github.com/css/csso) | +| [convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) | convert styles into attributes | +| [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) | convert colors (from `rgb()` to `#rrggbb`, from `#rrggbb` to `#rgb`) | +| [convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) | convert Path data to relative or absolute (whichever is shorter), convert one segment to another, trim useless delimiters, smart rounding, and much more | +| [convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) | collapse multiple transforms into one, convert matrices to the short aliases, and much more | +| [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) | remove unknown elements content and attributes, remove attrs with default values | +| [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | remove non-inheritable group's "presentation" attributes | +| [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | remove useless `stroke` and `fill` attrs | +| [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | remove unused namespaces declaration | +| [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | remove unused and minify used IDs | +| [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | round numeric values to the fixed precision, remove default `px` units | +| [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) | round numeric values in attributes that take a list of numbers (like `viewBox` or `enableBackground`) | +| [moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) | move elements' attributes to their enclosing group | +| [moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) | move some group attributes to the contained elements | +| [collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) | collapse useless groups | +| [removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) | remove raster images (disabled by default) | +| [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) | merge multiple Paths into one | +| [convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) | convert some basic shapes to `<path>` | +| [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | sort element attributes for epic readability (disabled by default) | +| [transformsWithOnePath](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) | apply transforms, crop by real width, center vertical alignment, and resize SVG with one Path inside (disabled by default) | +| [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | remove `width`/`height` attributes if `viewBox` is present (disabled by default) | +| [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | remove attributes by pattern (disabled by default) | +| [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | remove arbitrary elements by ID or className (disabled by default) | +| [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | add classnames to an outer `<svg>` element (disabled by default) | +| [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | adds attributes to an outer `<svg>` element (disabled by default) | +| [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | remove `<style>` elements (disabled by default) | + +Want to know how it works and how to write your own plugin? [Of course you want to](https://github.com/svg/svgo/blob/master/docs/how-it-works/en.md). ([동작방법](https://github.com/svg/svgo/blob/master/docs/how-it-works/ko.md)) + + +## How to use + +```sh +$ [sudo] npm install -g svgo +``` + +``` +Usage: + svgo [OPTIONS] [ARGS] + +Options: + -h, --help : Help + -v, --version : Version + -i INPUT, --input=INPUT : Input file, "-" for STDIN + -s STRING, --string=STRING : Input SVG data string + -f FOLDER, --folder=FOLDER : Input folder, optimize and rewrite all *.svg files + -o OUTPUT, --output=OUTPUT : Output file or folder (by default the same as the input), "-" for STDOUT + -p PRECISION, --precision=PRECISION : Set number of digits in the fractional part, overrides plugins params + --config=CONFIG : Config file or JSON string to extend or replace default + --disable=DISABLE : Disable plugin by name + --enable=ENABLE : Enable plugin by name + --datauri=DATAURI : Output as Data URI string (base64, URI encoded or unencoded) + --multipass : Enable multipass + --pretty : Make SVG pretty printed + --indent=INDENT : Indent number when pretty printing SVGs + -q, --quiet : Only output error messages, not regular status messages + --show-plugins : Show available plugins and exit + +Arguments: + INPUT : Alias to --input + OUTPUT : Alias to --output +``` + +* with files: + + $ svgo test.svg + + or: + + $ svgo test.svg test.min.svg + +* with STDIN / STDOUT: + + $ cat test.svg | svgo -i - -o - > test.min.svg + +* with folder + + $ svgo -f ../path/to/folder/with/svg/files + + or: + + $ svgo -f ../path/to/folder/with/svg/files -o ../path/to/folder/with/svg/output + +* with strings: + + $ svgo -s '<svg version="1.1">test</svg>' -o test.min.svg + + or even with Data URI base64: + + $ svgo -s 'data:image/svg+xml;base64,…' -o test.min.svg + +* with SVGZ: + + from `.svgz` to `.svg`: + + $ gunzip -c test.svgz | svgo -i - -o test.min.svg + + from `.svg` to `.svgz`: + + $ svgo test.svg -o - | gzip -cfq9 > test.svgz + +* with GUI – [svgo-gui](https://github.com/svg/svgo-gui) +* as a web app - [SVGOMG](https://jakearchibald.github.io/svgomg/) +* as a Nodejs module – [examples](https://github.com/svg/svgo/tree/master/examples) +* as a Grunt task – [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin) +* as a Gulp task – [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin) +* as a Mimosa module – [mimosa-minify-svg](https://github.com/dbashford/mimosa-minify-svg) +* as an OSX Folder Action – [svgo-osx-folder-action](https://github.com/svg/svgo-osx-folder-action) +* as a webpack loader – [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader) +* as a Telegram Bot – [svgo_bot](https://github.com/maksugr/svgo_bot) +* as a PostCSS plugin - [postcss-svgo](https://github.com/ben-eb/postcss-svgo) + +## License and copyrights + +This software is released under the terms of the [MIT license](https://github.com/svg/svgo/blob/master/LICENSE). + +Logo by [Yegor Bolshakov](http://xizzzy.ru/). diff --git a/node_modules/svgo/README.ru.md b/node_modules/svgo/README.ru.md new file mode 100644 index 00000000..ef236f38 --- /dev/null +++ b/node_modules/svgo/README.ru.md @@ -0,0 +1,155 @@ +[english](https://github.com/svg/svgo/blob/master/README.md) | **русский** +- - - + +<img src="https://svg.github.io/svgo-logo.svg" width="200" height="200" alt="logo"/> + +## SVGO [](https://npmjs.org/package/svgo) [](https://gemnasium.com/svg/svgo) [](https://travis-ci.org/svg/svgo) [](https://coveralls.io/r/svg/svgo?branch=master) + +**SVG** **O**ptimizer – это инструмент для оптимизации векторной графики в формате SVG, написанный на Node.js. + + +## Зачем? + +SVG-файлы, особенно – экспортированные из различных редакторов, содержат много избыточной и бесполезной информации, комментариев, скрытых элементов, неоптимальные или стандартные значения и другой мусор, удаление которого безопасно и не влияет на конечный результат отрисовки. + +## Возможности + +SVGO имеет расширяемую архитектуру, в которой почти каждая оптимизация является отдельным расширением. + +Сегодня у нас есть: + +| Plugin | Description | +| ------ | ----------- | +| [cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) | удаление переносов строк и лишних пробелов | +| [removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) | удаление doctype | +| [removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) | удаление XML-инструкций | +| [removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) | удаление комментариев | +| [removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) | удаление `<metadata>` | +| [removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) | удаление `<title>` (выключено по умолчанию) | +| [removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) | удаление `<desc>` (по умолчанию только незначимых) | +| [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) | удаление элементов в `<defs>` без `id` | +| [removeXMLNS](https://github.com/svg/svgo/blob/master/plugins/removeXMLNS.js) | удаление атрибута xmlns (для заинлайненных svg, выключено по умолчанию) | +| [removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) | удаление пространств имён различных редакторов, их элементов и атрибутов | +| [removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) | удаление пустых атрибутов | +| [removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) | удаление скрытых элементов | +| [removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) | удаление пустых текстовых элементов | +| [removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) | удаление пустых элементов-контейнеров | +| [removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) | удаление атрибута `viewBox`, когда это возможно | +| [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) | удаление или оптимизация атрибута `enable-background`, когда это возможно | +| [minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js) | уменьшает содержимое элементов `<style>` с помощью [CSSO](https://github.com/css/csso). | +| [convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) | конвертирование стилей в атрибуте `style` в отдельные svg-атрибуты | +| [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) | конвертирование цветовых значений: из `rgb()` в `#rrggbb`, из `#rrggbb` в `#rgb` | +| [convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) | конвертирование данных Path в относительные или абсолютные координаты, смотря что |короче; конвертирование одних типов сегментов в другие; удаление ненужных разделителей; умное округление и тому подобное +| [convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) | схлопывание нескольких трансформаций в одну, конвертирование матриц в короткие алиасы |и многое другое +| [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) | удаление неизвестных элементов, контента и атрибутов | +| [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | удаление ненаследуемых "презентационных" атрибутов групп | +| [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | удаление неиспользуемых атрибутов stroke-* и fill-* | +| [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | удаление деклараций неиспользуемых пространств имён | +| [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | удаление неиспользуемых и сокращение используемых ID | +| [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | округление дробных чисел до заданной точности, удаление `px` как единицы |измерения по-умолчанию +| [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) | округление числовых значений в атрибутах со списком чисел, таких как `viewBox` |или `enableBackground` +| [moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) | перемещение совпадающих атрибутов у всех элементов внутри группы `<g>` | +| [moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) | перемещение некоторых атрибутов группы на элементы внутри | +| [collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) | схлопывание бесполезных групп `<g>` | +| [removeRasterImage](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) | удаление растровых изображений (выключено по умолчанию) | +| [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) | склеивание нескольких Path в одну кривую | +| [convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) | конвертирование простых форм в Path | +| [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | сортировка атрибутов элементов для удобочитаемости (выключено по умолчанию) | +| [transformsWithOnePath](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) | применение трансформаций, обрезка по реальной ширине, вертикальное |выравнивание по центру и изменение размеров SVG с одним Path внутри +| [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | удаляет атрибуты width/height при наличии viewBox (выключено по умолчанию) | +| [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | удаляет атрибуты по указанному паттерну (выключено по умолчанию) | +| [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | удаляет элементы по указанным ID или классам (выключено по умолчанию) | +| [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | добавляет имена классов корневому элементу `<svg>` (выключено по умолчанию) | +| [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | добавляет атрибуты корневому элементу `<svg>` (выключено |по умолчанию) +| [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | удаляет элементы `<style>` (выключено по умолчанию) | + +Хотите узнать, как это работает и как написать свой плагин? [Конечно же, да!](https://github.com/svg/svgo/blob/master/docs/how-it-works/ru.md). + + +## Как использовать + +```sh +$ [sudo] npm install -g svgo +``` + +``` +Выполнение: + svgo [OPTIONS] [ARGS] + +Параметры: + -h, --help : Помощь + -v, --version : Версия программы + -i INPUT, --input=INPUT : Входной файл, "-" для STDIN + -s STRING, --string=STRING : Входная строка SVG + -f FOLDER, --folder=FOLDER : Входная папка, оптимизирует и перезаписывает все файлы *.svg + -o OUTPUT, --output=OUTPUT : Выходной файл или папка (совпадает с входным по умолчанию), "-" для STDOUT + -p PRECISION, --precision=PRECISION : Число цифр после запятой, переопределяет параметры плагинов + --config=CONFIG : Файл конфигурации (или строка JSON) для расширения и замены настроек + --disable=DISABLE : Выключение плагина по имени + --enable=ENABLE : Включение плагина по имени + --datauri=DATAURI : Результат в виде строки Data URI (base64, URI encoded или unencoded) + --multipass : Оптимизация в несколько проходов + --pretty : Удобочитаемое форматирование SVG + --indent=INDENT : Размер отступа для удобочитаемого форматирования + -q, --quiet : Подавляет вывод информации, выводятся только сообщения об ошибках + --show-plugins : Доступные плагины + +Аргументы: + INPUT : Аналогично --input + OUTPUT : Аналогично --output +``` + +* с файлами: + + $ svgo test.svg + + или: + + $ svgo test.svg test.min.svg + +* со STDIN / STDOUT: + + $ cat test.svg | svgo -i - -o - > test.min.svg + +* с папками + + $ svgo -f ../path/to/folder/with/svg/files + + или: + + $ svgo -f ../path/to/folder/with/svg/files -o ../path/to/folder/with/svg/output + +* со строками: + + $ svgo -s '<svg version="1.1">test</svg>' -o test.min.svg + + или даже с Data URI base64: + + $ svgo -s 'data:image/svg+xml;base64,…' -o test.min.svg + +* с SVGZ: + + из `.svgz` в `.svg`: + + $ gunzip -c test.svgz | svgo -i - -o test.min.svg + + из `.svg` в `.svgz`: + + $ svgo test.svg -o - | gzip -cfq9 > test.svgz + +* с помощью GUI – [svgo-gui](https://github.com/svg/svgo-gui) +* в виде веб-приложения - [SVGOMG](https://jakearchibald.github.io/svgomg/) +* как модуль Node.js – [examples](https://github.com/svg/svgo/tree/master/examples) +* как таск для Grunt – [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin) +* как таск для Gulp – [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin) +* как таск для Mimosa – [mimosa-minify-svg](https://github.com/dbashford/mimosa-minify-svg) +* как действие папки в OSX – [svgo-osx-folder-action](https://github.com/svg/svgo-osx-folder-action) +* через загрузчик в webpack – [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader) +* с помощью бота в Telegram – [svgo_bot](https://github.com/maksugr/svgo_bot) +* как плагин PostCSS - [postcss-svgo](https://github.com/ben-eb/postcss-svgo) + +## Лицензия и копирайты + +Данное программное обеспечение выпускается под [лицензией MIT](https://github.com/svg/svgo/blob/master/LICENSE). + +Логотип – [Егор Большаков](http://xizzzy.ru/). diff --git a/node_modules/svgo/bin/svgo b/node_modules/svgo/bin/svgo new file mode 100755 index 00000000..2fd77c02 --- /dev/null +++ b/node_modules/svgo/bin/svgo @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../lib/svgo/coa').run(); diff --git a/node_modules/svgo/lib/svgo.js b/node_modules/svgo/lib/svgo.js new file mode 100644 index 00000000..c593023f --- /dev/null +++ b/node_modules/svgo/lib/svgo.js @@ -0,0 +1,80 @@ +'use strict'; + +/** + * SVGO is a Nodejs-based tool for optimizing SVG vector graphics files. + * + * @see https://github.com/svg/svgo + * + * @author Kir Belevich <kir@soulshine.in> (https://github.com/deepsweet) + * @copyright © 2012 Kir Belevich + * @license MIT https://raw.githubusercontent.com/svg/svgo/master/LICENSE + */ + +var CONFIG = require('./svgo/config.js'), + SVG2JS = require('./svgo/svg2js.js'), + PLUGINS = require('./svgo/plugins.js'), + JSAPI = require('./svgo/jsAPI.js'), + JS2SVG = require('./svgo/js2svg.js'); + +var SVGO = module.exports = function(config) { + + this.config = CONFIG(config); + +}; + +SVGO.prototype.optimize = function(svgstr, callback) { + if (this.config.error) return callback(this.config); + + var _this = this, + config = this.config, + maxPassCount = config.multipass ? 10 : 1, + counter = 0, + prevResultSize = Number.POSITIVE_INFINITY, + optimizeOnceCallback = function(svgjs) { + + if (svgjs.error) { + callback(svgjs); + return; + } + + if (++counter < maxPassCount && svgjs.data.length < prevResultSize) { + prevResultSize = svgjs.data.length; + _this._optimizeOnce(svgjs.data, optimizeOnceCallback); + } else { + callback(svgjs); + } + + }; + + _this._optimizeOnce(svgstr, optimizeOnceCallback); + +}; + +SVGO.prototype._optimizeOnce = function(svgstr, callback) { + var config = this.config; + + SVG2JS(svgstr, function(svgjs) { + + if (svgjs.error) { + callback(svgjs); + return; + } + + svgjs = PLUGINS(svgjs, config.plugins); + + callback(JS2SVG(svgjs, config.js2svg)); + + }); +}; + +/** + * The factory that creates a content item with the helper methods. + * + * @param {Object} data which passed to jsAPI constructor + * @returns {JSAPI} content item + */ +SVGO.prototype.createContentItem = function(data) { + + return new JSAPI(data); + +}; diff --git a/node_modules/svgo/lib/svgo/coa.js b/node_modules/svgo/lib/svgo/coa.js new file mode 100644 index 00000000..6b482231 --- /dev/null +++ b/node_modules/svgo/lib/svgo/coa.js @@ -0,0 +1,581 @@ +/* jshint quotmark: false */ +'use strict'; + +require('colors'); + +var FS = require('fs'), + PATH = require('path'), + SVGO = require('../svgo.js'), + YAML = require('js-yaml'), + PKG = require('../../package.json'), + mkdirp = require('mkdirp'), + encodeSVGDatauri = require('./tools.js').encodeSVGDatauri, + decodeSVGDatauri = require('./tools.js').decodeSVGDatauri, + regSVGFile = /\.svg$/; + +/** + * Command-Option-Argument. + * + * @see https://github.com/veged/coa + */ +module.exports = require('coa').Cmd() + .helpful() + .name(PKG.name) + .title(PKG.description) + .opt() + .name('version').title('Version') + .short('v').long('version') + .only() + .flag() + .act(function() { + // output the version to stdout instead of stderr if returned + process.stdout.write(PKG.version + '\n'); + // coa will run `.toString` on the returned value and send it to stderr + return ''; + }) + .end() + .opt() + .name('input').title('Input file, "-" for STDIN') + .short('i').long('input') + .val(function(val) { + return val || this.reject("Option '--input' must have a value."); + }) + .end() + .opt() + .name('string').title('Input SVG data string') + .short('s').long('string') + .end() + .opt() + .name('folder').title('Input folder, optimize and rewrite all *.svg files') + .short('f').long('folder') + .val(function(val) { + return val || this.reject("Option '--folder' must have a value."); + }) + .end() + .opt() + .name('output').title('Output file or folder (by default the same as the input), "-" for STDOUT') + .short('o').long('output') + .val(function(val) { + return val || this.reject("Option '--output' must have a value."); + }) + .end() + .opt() + .name('precision').title('Set number of digits in the fractional part, overrides plugins params') + .short('p').long('precision') + .val(function(val) { + return !isNaN(val) ? val : this.reject("Option '--precision' must be an integer number"); + }) + .end() + .opt() + .name('config').title('Config file or JSON string to extend or replace default') + .long('config') + .val(function(val) { + return val || this.reject("Option '--config' must have a value."); + }) + .end() + .opt() + .name('disable').title('Disable plugin by name') + .long('disable') + .arr() + .val(function(val) { + return val || this.reject("Option '--disable' must have a value."); + }) + .end() + .opt() + .name('enable').title('Enable plugin by name') + .long('enable') + .arr() + .val(function(val) { + return val || this.reject("Option '--enable' must have a value."); + }) + .end() + .opt() + .name('datauri').title('Output as Data URI string (base64, URI encoded or unencoded)') + .long('datauri') + .val(function(val) { + return val || this.reject("Option '--datauri' must have one of the following values: 'base64', 'enc' or 'unenc'"); + }) + .end() + .opt() + .name('multipass').title('Enable multipass') + .long('multipass') + .flag() + .end() + .opt() + .name('pretty').title('Make SVG pretty printed') + .long('pretty') + .flag() + .end() + .opt() + .name('indent').title('Indent number when pretty printing SVGs') + .long('indent') + .val(function(val) { + return !isNaN(val) ? val : this.reject("Option '--indent' must be an integer number"); + }) + .end() + .opt() + .name('quiet').title('Only output error messages, not regular status messages') + .short('q').long('quiet') + .flag() + .end() + .opt() + .name('show-plugins').title('Show available plugins and exit') + .long('show-plugins') + .flag() + .end() + .arg() + .name('input').title('Alias to --input') + .end() + .arg() + .name('output').title('Alias to --output') + .end() + .act(function(opts, args) { + + var input = args && args.input ? args.input : opts.input, + output = args && args.output ? args.output : opts.output, + config = {}; + + // --show-plugins + if (opts['show-plugins']) { + + showAvailablePlugins(); + process.exit(0); + + } + + // w/o anything + if ( + (!input || input === '-') && + !opts.string && + !opts.stdin && + !opts.folder && + process.stdin.isTTY + ) return this.usage(); + + + // --config + if (opts.config) { + + // string + if (opts.config.charAt(0) === '{') { + try { + config = JSON.parse(opts.config); + } catch (e) { + console.error("Error: Couldn't parse config JSON."); + console.error(String(e)); + return; + } + + // external file + } else { + var configPath = PATH.resolve(opts.config); + try { + // require() adds some weird output on YML files + config = JSON.parse(FS.readFileSync(configPath, 'utf8')); + } catch (err) { + if (err.code === 'ENOENT') { + console.error('Error: couldn\'t find config file \'' + opts.config + '\'.'); + return; + } else if (err.code === 'EISDIR') { + console.error('Error: directory \'' + opts.config + '\' is not a config file.'); + return; + } + config = YAML.safeLoad(FS.readFileSync(configPath, 'utf8')); + + if (!config || Array.isArray(config)) { + console.error('Error: invalid config file \'' + opts.config + '\'.'); + return; + } + } + } + + } + + // --quiet + if (opts.quiet) { + config.quiet = opts.quiet; + } + + // --precision + if (opts.precision) { + config.floatPrecision = Math.max(0, parseInt(opts.precision)); + } + + // --disable + if (opts.disable) { + changePluginsState(opts.disable, false, config); + } + + // --enable + if (opts.enable) { + changePluginsState(opts.enable, true, config); + } + + // --multipass + if (opts.multipass) { + + config.multipass = true; + + } + + // --pretty + if (opts.pretty) { + + config.js2svg = config.js2svg || {}; + config.js2svg.pretty = true; + if (opts.indent) { + config.js2svg.indent = parseInt(opts.indent, 10); + } + + } + + // --output + if (opts.output) { + config.output = opts.output; + } + + // --folder + if (opts.folder) { + optimizeFolder(opts.folder, config, output); + + return; + } + + // --input + if (input) { + + // STDIN + if (input === '-') { + + var data = ''; + + process.stdin.pause(); + + process.stdin + .on('data', function(chunk) { + data += chunk; + }) + .once('end', function() { + optimizeFromString(data, config, opts.datauri, input, output); + }) + .resume(); + + // file + } else { + + FS.readFile(input, 'utf8', function(err, data) { + if (err) { + if (err.code === 'EISDIR') + optimizeFolder(input, config, output); + else if (err.code === 'ENOENT') + console.error('Error: no such file or directory \'' + input + '\'.'); + else + console.error(err); + return; + } + optimizeFromString(data, config, opts.datauri, input, output); + }); + + } + + // --string + } else if (opts.string) { + + opts.string = decodeSVGDatauri(opts.string); + + optimizeFromString(opts.string, config, opts.datauri, input, output); + + } + }); + +function optimizeFromString(svgstr, config, datauri, input, output) { + + var startTime = Date.now(config), + time, + inBytes = Buffer.byteLength(svgstr, 'utf8'), + outBytes, + svgo = new SVGO(config); + + svgo.optimize(svgstr, function(result) { + + if (result.error) { + console.error(result.error); + return; + } + + if (datauri) { + result.data = encodeSVGDatauri(result.data, datauri); + } + + outBytes = Buffer.byteLength(result.data, 'utf8'); + time = Date.now() - startTime; + + // stdout + if (output === '-' || (!input || input === '-') && !output) { + + process.stdout.write(result.data + '\n'); + + // file + } else { + + // overwrite input file if there is no output + if (!output && input) { + output = input; + } + + if (!config.quiet) { + console.log('\r'); + } + + saveFileAndPrintInfo(config, result.data, output, inBytes, outBytes, time); + + } + + }); + +} + +function saveFileAndPrintInfo(config, data, path, inBytes, outBytes, time) { + + FS.writeFile(path, data, 'utf8', function() { + if (config.quiet) { + return; + } + + // print time info + printTimeInfo(time); + + // print optimization profit info + printProfitInfo(inBytes, outBytes); + + }); + +} + +function printTimeInfo(time) { + console.log('Done in ' + time + ' ms!'); + +} + +function printProfitInfo(inBytes, outBytes) { + + var profitPercents = 100 - outBytes * 100 / inBytes; + + console.log( + (Math.round((inBytes / 1024) * 1000) / 1000) + ' KiB' + + (profitPercents < 0 ? ' + ' : ' - ') + + String(Math.abs((Math.round(profitPercents * 10) / 10)) + '%').green + ' = ' + + (Math.round((outBytes / 1024) * 1000) / 1000) + ' KiB\n' + ); + +} + +/** + * Change plugins state by names array. + * + * @param {Array} names plugins names + * @param {Boolean} state active state + * @param {Object} config original config + * @return {Object} changed config + */ +function changePluginsState(names, state, config) { + + // extend config + if (config.plugins) { + + names.forEach(function(name) { + + var matched, + key; + + config.plugins.forEach(function(plugin) { + + // get plugin name + if (typeof plugin === 'object') { + key = Object.keys(plugin)[0]; + } else { + key = plugin; + } + + // if there is such a plugin name + if (key === name) { + // don't replace plugin's params with true + if (typeof plugin[key] !== 'object' || !state) { + plugin[key] = state; + } + + // mark it as matched + matched = true; + } + + }); + + // if not matched and current config is not full + if (!matched && !config.full) { + + var obj = {}; + + obj[name] = state; + + // push new plugin Object + config.plugins.push(obj); + + matched = true; + + } + + }); + + // just push + } else { + + config.plugins = []; + + names.forEach(function(name) { + var obj = {}; + + obj[name] = state; + + config.plugins.push(obj); + }); + + } + + return config; + +} + +function optimizeFolder(dir, config, output) { + + var svgo = new SVGO(config); + + if (!config.quiet) { + console.log('Processing directory \'' + dir + '\':\n'); + } + + // absoluted folder path + var path = PATH.resolve(dir); + + // list folder content + FS.readdir(path, function(err, files) { + + if (err) { + console.error(err); + return; + } + + if (!files.length) { + console.log('Directory \'' + dir + '\' is empty.'); + return; + } + + var i = 0, + found = false; + + function optimizeFile(file) { + + // absoluted file path + var filepath = PATH.resolve(path, file); + var outfilepath = output ? PATH.resolve(output, file) : filepath; + + // check if file name matches *.svg + if (regSVGFile.test(filepath)) { + + found = true; + FS.readFile(filepath, 'utf8', function(err, data) { + + if (err) { + console.error(err); + return; + } + + var startTime = Date.now(), + time, + inBytes = Buffer.byteLength(data, 'utf8'), + outBytes; + + svgo.optimize(data, function(result) { + + if (result.error) { + console.error(result.error); + return; + } + + outBytes = Buffer.byteLength(result.data, 'utf8'); + time = Date.now() - startTime; + + writeOutput(); + + function writeOutput() { + FS.writeFile(outfilepath, result.data, 'utf8', report); + } + + function report(err) { + + if (err) { + if (err.code === 'ENOENT') { + mkdirp(output, writeOutput); + return; + } else if (err.code === 'ENOTDIR') { + console.error('Error: output \'' + output + '\' is not a directory.'); + return; + } + console.error(err); + return; + } + + if (!config.quiet) { + console.log(file + ':'); + + // print time info + printTimeInfo(time); + + // print optimization profit info + printProfitInfo(inBytes, outBytes); + } + + //move on to the next file + if (++i < files.length) { + optimizeFile(files[i]); + } + + } + + }); + + }); + + } + //move on to the next file + else if (++i < files.length) { + optimizeFile(files[i]); + } else if (!found) { + console.log('No SVG files have been found.'); + } + + + } + + optimizeFile(files[i]); + + }); + +} + + +var showAvailablePlugins = function () { + + var svgo = new SVGO(), + // Flatten an array of plugins grouped per type and sort alphabetically + list = Array.prototype.concat.apply([], svgo.config.plugins).sort(function(a, b) { + return a.name > b.name ? 1 : -1; + }); + + console.log('Currently available plugins:'); + + list.forEach(function (plugin) { + console.log(' [ ' + plugin.name.green + ' ] ' + plugin.description); + }); + + //console.log(JSON.stringify(svgo, null, 4)); +}; diff --git a/node_modules/svgo/lib/svgo/config.js b/node_modules/svgo/lib/svgo/config.js new file mode 100644 index 00000000..093067d4 --- /dev/null +++ b/node_modules/svgo/lib/svgo/config.js @@ -0,0 +1,212 @@ +'use strict'; + +var FS = require('fs'); +var yaml = require('js-yaml'); + +var EXTEND = require('whet.extend'); + +/** + * Read and/or extend/replace default config file, + * prepare and optimize plugins array. + * + * @param {Object} [config] input config + * @return {Object} output config + */ +module.exports = function(config) { + + var defaults; + config = typeof config == 'object' && config || {}; + + if (config.plugins && !Array.isArray(config.plugins)) { + return { error: 'Error: Invalid plugins list. Provided \'plugins\' in config should be an array.' }; + } + + if (config.full) { + defaults = config; + + if (Array.isArray(defaults.plugins)) { + defaults.plugins = preparePluginsArray(defaults.plugins); + } + } else { + defaults = EXTEND({}, yaml.safeLoad(FS.readFileSync(__dirname + '/../../.svgo.yml', 'utf8'))); + defaults.plugins = preparePluginsArray(defaults.plugins); + defaults = extendConfig(defaults, config); + } + + if ('floatPrecision' in config && Array.isArray(defaults.plugins)) { + defaults.plugins.forEach(function(plugin) { + if (plugin.params && ('floatPrecision' in plugin.params)) { + // Don't touch default plugin params + plugin.params = EXTEND({}, plugin.params, { floatPrecision: config.floatPrecision }); + } + }); + } + + if (Array.isArray(defaults.plugins)) { + defaults.plugins = optimizePluginsArray(defaults.plugins); + } + + return defaults; + +}; + +/** + * Require() all plugins in array. + * + * @param {Array} plugins input plugins array + * @return {Array} input plugins array of arrays + */ +function preparePluginsArray(plugins) { + + var plugin, + key; + + return plugins.map(function(item) { + + // {} + if (typeof item === 'object') { + + key = Object.keys(item)[0]; + + // custom + if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') { + plugin = setupCustomPlugin(key, item[key]); + + } else { + + plugin = EXTEND({}, require('../../plugins/' + key)); + + // name: {} + if (typeof item[key] === 'object') { + plugin.params = EXTEND({}, plugin.params || {}, item[key]); + plugin.active = true; + + // name: false + } else if (item[key] === false) { + plugin.active = false; + + // name: true + } else if (item[key] === true) { + plugin.active = true; + } + + plugin.name = key; + } + + // name + } else { + + plugin = EXTEND({}, require('../../plugins/' + item)); + plugin.name = item; + + } + + return plugin; + + }); + +} + +/** + * Extend plugins with the custom config object. + * + * @param {Array} plugins input plugins + * @param {Object} config config + * @return {Array} output plugins + */ +function extendConfig(defaults, config) { + + var key; + + // plugins + if (config.plugins) { + + config.plugins.forEach(function(item) { + + // {} + if (typeof item === 'object') { + + key = Object.keys(item)[0]; + + // custom + if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') { + defaults.plugins.push(setupCustomPlugin(key, item[key])); + + } else { + defaults.plugins.forEach(function(plugin) { + + if (plugin.name === key) { + // name: {} + if (typeof item[key] === 'object') { + plugin.params = EXTEND({}, plugin.params || {}, item[key]); + plugin.active = true; + + // name: false + } else if (item[key] === false) { + plugin.active = false; + + // name: true + } else if (item[key] === true) { + plugin.active = true; + } + } + }); + } + + } + + }); + + } + + defaults.multipass = config.multipass; + + // svg2js + if (config.svg2js) { + defaults.svg2js = config.svg2js; + } + + // js2svg + if (config.js2svg) { + defaults.js2svg = config.js2svg; + } + + return defaults; + +} + +/** + * Setup and enable a custom plugin + * + * @param {String} plugin name + * @param {Object} custom plugin + * @return {Array} enabled plugin + */ +function setupCustomPlugin(name, plugin) { + plugin.active = true; + plugin.params = EXTEND({}, plugin.params || {}); + plugin.name = name; + + return plugin; +} + +/** + * Try to group sequential elements of plugins array. + * + * @param {Object} plugins input plugins + * @return {Array} output plugins + */ +function optimizePluginsArray(plugins) { + + var prev; + + return plugins.reduce(function(plugins, item) { + if (prev && item.type == prev[0].type) { + prev.push(item); + } else { + plugins.push(prev = [item]); + } + return plugins; + }, []); + +} diff --git a/node_modules/svgo/lib/svgo/js2svg.js b/node_modules/svgo/lib/svgo/js2svg.js new file mode 100644 index 00000000..5d19cc8d --- /dev/null +++ b/node_modules/svgo/lib/svgo/js2svg.js @@ -0,0 +1,352 @@ +'use strict'; + +var EOL = require('os').EOL, + EXTEND = require('whet.extend'), + textElem = require('../../plugins/_collections.js').elemsGroups.textContent.concat('title'); + +var defaults = { + doctypeStart: '<!DOCTYPE', + doctypeEnd: '>', + procInstStart: '<?', + procInstEnd: '?>', + tagOpenStart: '<', + tagOpenEnd: '>', + tagCloseStart: '</', + tagCloseEnd: '>', + tagShortStart: '<', + tagShortEnd: '/>', + attrStart: '="', + attrEnd: '"', + commentStart: '<!--', + commentEnd: '-->', + cdataStart: '<![CDATA[', + cdataEnd: ']]>', + textStart: '', + textEnd: '', + indent: 4, + regEntities: /[&'"<>]/g, + regValEntities: /[&"<>]/g, + encodeEntity: encodeEntity, + pretty: false, + useShortTags: true +}; + +var entities = { + '&': '&', + '\'': ''', + '"': '"', + '>': '>', + '<': '<', + }; + +/** + * Convert SVG-as-JS object to SVG (XML) string. + * + * @param {Object} data input data + * @param {Object} config config + * + * @return {Object} output data + */ +module.exports = function(data, config) { + + return new JS2SVG(config).convert(data); + +}; + +function JS2SVG(config) { + + if (config) { + this.config = EXTEND(true, {}, defaults, config); + } else { + this.config = defaults; + } + + var indent = this.config.indent; + if (typeof indent == 'number' && !isNaN(indent)) { + this.config.indent = ''; + for (var i = indent; i-- > 0;) this.config.indent += ' '; + } else if (typeof indent != 'string') { + this.config.indent = ' '; + } + + if (this.config.pretty) { + this.config.doctypeEnd += EOL; + this.config.procInstEnd += EOL; + this.config.commentEnd += EOL; + this.config.cdataEnd += EOL; + this.config.tagShortEnd += EOL; + this.config.tagOpenEnd += EOL; + this.config.tagCloseEnd += EOL; + this.config.textEnd += EOL; + } + + this.indentLevel = 0; + this.textContext = null; + +} + +function encodeEntity(char) { + return entities[char]; +} + +/** + * Start conversion. + * + * @param {Object} data input data + * + * @return {String} + */ +JS2SVG.prototype.convert = function(data) { + + var svg = ''; + + if (data.content) { + + this.indentLevel++; + + data.content.forEach(function(item) { + + if (item.elem) { + svg += this.createElem(item); + } else if (item.text) { + svg += this.createText(item.text); + } else if (item.doctype) { + svg += this.createDoctype(item.doctype); + } else if (item.processinginstruction) { + svg += this.createProcInst(item.processinginstruction); + } else if (item.comment) { + svg += this.createComment(item.comment); + } else if (item.cdata) { + svg += this.createCDATA(item.cdata); + } + + }, this); + + } + + this.indentLevel--; + + return { + data: svg, + info: { + width: this.width, + height: this.height + } + }; + +}; + +/** + * Create indent string in accordance with the current node level. + * + * @return {String} + */ +JS2SVG.prototype.createIndent = function() { + + var indent = ''; + + if (this.config.pretty && !this.textContext) { + for (var i = 1; i < this.indentLevel; i++) { + indent += this.config.indent; + } + } + + return indent; + +}; + +/** + * Create doctype tag. + * + * @param {String} doctype doctype body string + * + * @return {String} + */ +JS2SVG.prototype.createDoctype = function(doctype) { + + return this.config.doctypeStart + + doctype + + this.config.doctypeEnd; + +}; + +/** + * Create XML Processing Instruction tag. + * + * @param {Object} instruction instruction object + * + * @return {String} + */ +JS2SVG.prototype.createProcInst = function(instruction) { + + return this.config.procInstStart + + instruction.name + + ' ' + + instruction.body + + this.config.procInstEnd; + +}; + +/** + * Create comment tag. + * + * @param {String} comment comment body + * + * @return {String} + */ +JS2SVG.prototype.createComment = function(comment) { + + return this.config.commentStart + + comment + + this.config.commentEnd; + +}; + +/** + * Create CDATA section. + * + * @param {String} cdata CDATA body + * + * @return {String} + */ +JS2SVG.prototype.createCDATA = function(cdata) { + + return this.createIndent() + + this.config.cdataStart + + cdata + + this.config.cdataEnd; + +}; + +/** + * Create element tag. + * + * @param {Object} data element object + * + * @return {String} + */ +JS2SVG.prototype.createElem = function(data) { + + // beautiful injection for obtaining SVG information :) + if ( + data.isElem('svg') && + data.hasAttr('width') && + data.hasAttr('height') + ) { + this.width = data.attr('width').value; + this.height = data.attr('height').value; + } + + // empty element and short tag + if (data.isEmpty()) { + if (this.config.useShortTags) { + return this.createIndent() + + this.config.tagShortStart + + data.elem + + this.createAttrs(data) + + this.config.tagShortEnd; + } else { + return this.createIndent() + + this.config.tagShortStart + + data.elem + + this.createAttrs(data) + + this.config.tagOpenEnd + + this.config.tagCloseStart + + data.elem + + this.config.tagCloseEnd; + } + // non-empty element + } else { + var tagOpenStart = this.config.tagOpenStart, + tagOpenEnd = this.config.tagOpenEnd, + tagCloseStart = this.config.tagCloseStart, + tagCloseEnd = this.config.tagCloseEnd, + openIndent = this.createIndent(), + textIndent = '', + processedData = '', + dataEnd = ''; + + if (this.textContext) { + tagOpenStart = defaults.tagOpenStart; + tagOpenEnd = defaults.tagOpenEnd; + tagCloseStart = defaults.tagCloseStart; + tagCloseEnd = defaults.tagCloseEnd; + openIndent = ''; + } else if (data.isElem(textElem)) { + if (this.config.pretty) { + textIndent += openIndent + this.config.indent; + } + this.textContext = data; + } + + processedData += this.convert(data).data; + + if (this.textContext == data) { + this.textContext = null; + if (this.config.pretty) dataEnd = EOL; + } + + return openIndent + + tagOpenStart + + data.elem + + this.createAttrs(data) + + tagOpenEnd + + textIndent + + processedData + + dataEnd + + this.createIndent() + + tagCloseStart + + data.elem + + tagCloseEnd; + + } + +}; + +/** + * Create element attributes. + * + * @param {Object} elem attributes object + * + * @return {String} + */ +JS2SVG.prototype.createAttrs = function(elem) { + + var attrs = ''; + + elem.eachAttr(function(attr) { + + if (attr.value !== undefined) { + attrs += ' ' + + attr.name + + this.config.attrStart + + String(attr.value).replace(this.config.regValEntities, this.config.encodeEntity) + + this.config.attrEnd; + } + else { + attrs += ' ' + + attr.name; + } + + + }, this); + + return attrs; + +}; + +/** + * Create text node. + * + * @param {String} text text + * + * @return {String} + */ +JS2SVG.prototype.createText = function(text) { + + return this.createIndent() + + this.config.textStart + + text.replace(this.config.regEntities, this.config.encodeEntity) + + (this.textContext ? '' : this.config.textEnd); + +}; diff --git a/node_modules/svgo/lib/svgo/jsAPI.js b/node_modules/svgo/lib/svgo/jsAPI.js new file mode 100644 index 00000000..1e2f55fb --- /dev/null +++ b/node_modules/svgo/lib/svgo/jsAPI.js @@ -0,0 +1,298 @@ +'use strict'; + +var EXTEND = require('whet.extend'); + +var JSAPI = module.exports = function(data, parentNode) { + EXTEND(this, data); + if (parentNode) { + Object.defineProperty(this, 'parentNode', { + writable: true, + value: parentNode + }); + } +}; + +/** + * Perform a deep clone of this node. + * + * @return {Object} element + */ +JSAPI.prototype.clone = function() { + var node = this; + var nodeData = {}; + + Object.keys(node).forEach(function(key) { + if (key !== 'content') { + nodeData[key] = node[key]; + } + }); + + // Deep-clone node data + // This is still faster than using EXTEND(true…) + nodeData = JSON.parse(JSON.stringify(nodeData)); + + // parentNode gets set to a proper object by the parent clone, + // but it needs to be true/false now to do the right thing + // in the constructor. + var clonedNode = new JSAPI(nodeData, !!node.parentNode); + + if (node.content) { + clonedNode.content = node.content.map(function(childNode) { + var clonedChild = childNode.clone(); + clonedChild.parentNode = clonedNode; + return clonedChild; + }); + } + + return clonedNode; +}; + +/** + * Determine if item is an element + * (any, with a specific name or in a names array). + * + * @param {String|Array} [param] element name or names arrays + * @return {Boolean} + */ +JSAPI.prototype.isElem = function(param) { + + if (!param) return !!this.elem; + + if (Array.isArray(param)) return !!this.elem && (param.indexOf(this.elem) > -1); + + return !!this.elem && this.elem === param; + +}; + +/** + * Renames an element + * + * @param {String} name new element name + * @return {Object} element + */ +JSAPI.prototype.renameElem = function(name) { + + if (name && typeof name === 'string') + this.elem = this.local = name; + + return this; + +}; + +/** + * Determine if element is empty. + * + * @return {Boolean} + */ + JSAPI.prototype.isEmpty = function() { + + return !this.content || !this.content.length; + +}; + +/** + * Changes content by removing elements and/or adding new elements. + * + * @param {Number} start Index at which to start changing the content. + * @param {Number} n Number of elements to remove. + * @param {Array|Object} [insertion] Elements to add to the content. + * @return {Array} Removed elements. + */ + JSAPI.prototype.spliceContent = function(start, n, insertion) { + + if (arguments.length < 2) return []; + + if (!Array.isArray(insertion)) + insertion = Array.apply(null, arguments).slice(2); + + insertion.forEach(function(inner) { inner.parentNode = this }, this); + + return this.content.splice.apply(this.content, [start, n].concat(insertion)); + + +}; + +/** + * Determine if element has an attribute + * (any, or by name or by name + value). + * + * @param {String} [name] attribute name + * @param {String} [val] attribute value (will be toString()'ed) + * @return {Boolean} + */ + JSAPI.prototype.hasAttr = function(name, val) { + + if (!this.attrs || !Object.keys(this.attrs).length) return false; + + if (!arguments.length) return !!this.attrs; + + if (val !== undefined) return !!this.attrs[name] && this.attrs[name].value === val.toString(); + + return !!this.attrs[name]; + +}; + +/** + * Determine if element has an attribute by local name + * (any, or by name or by name + value). + * + * @param {String} [localName] local attribute name + * @param {Number|String|RegExp|Function} [val] attribute value (will be toString()'ed or executed, otherwise ignored) + * @return {Boolean} + */ + JSAPI.prototype.hasAttrLocal = function(localName, val) { + + if (!this.attrs || !Object.keys(this.attrs).length) return false; + + if (!arguments.length) return !!this.attrs; + + var callback; + + switch (val != null && val.constructor && val.constructor.name) { + case 'Number': // same as String + case 'String': callback = stringValueTest; break; + case 'RegExp': callback = regexpValueTest; break; + case 'Function': callback = funcValueTest; break; + default: callback = nameTest; + } + return this.someAttr(callback); + + function nameTest(attr) { + return attr.local === localName; + } + + function stringValueTest(attr) { + return attr.local === localName && val == attr.value; + } + + function regexpValueTest(attr) { + return attr.local === localName && val.test(attr.value); + } + + function funcValueTest(attr) { + return attr.local === localName && val(attr.value); + } + +}; + +/** + * Get a specific attribute from an element + * (by name or name + value). + * + * @param {String} name attribute name + * @param {String} [val] attribute value (will be toString()'ed) + * @return {Object|Undefined} + */ + JSAPI.prototype.attr = function(name, val) { + + if (!this.hasAttr() || !arguments.length) return undefined; + + if (val !== undefined) return this.hasAttr(name, val) ? this.attrs[name] : undefined; + + return this.attrs[name]; + +}; + +/** + * Get computed attribute value from an element + * + * @param {String} name attribute name + * @return {Object|Undefined} + */ + JSAPI.prototype.computedAttr = function(name, val) { + /* jshint eqnull: true */ + if (!arguments.length) return; + + for (var elem = this; elem && (!elem.hasAttr(name) || !elem.attr(name).value); elem = elem.parentNode); + + if (val != null) { + return elem ? elem.hasAttr(name, val) : false; + } else if (elem && elem.hasAttr(name)) { + return elem.attrs[name].value; + } + +}; + +/** + * Remove a specific attribute. + * + * @param {String|Array} name attribute name + * @param {String} [val] attribute value + * @return {Boolean} + */ + JSAPI.prototype.removeAttr = function(name, val, recursive) { + + if (!arguments.length) return false; + + if (Array.isArray(name)) name.forEach(this.removeAttr, this); + + if (!this.hasAttr(name)) return false; + + if (!recursive && val && this.attrs[name].value !== val) return false; + + delete this.attrs[name]; + + if (!Object.keys(this.attrs).length) delete this.attrs; + + return true; + +}; + +/** + * Add attribute. + * + * @param {Object} [attr={}] attribute object + * @return {Object|Boolean} created attribute or false if no attr was passed in + */ + JSAPI.prototype.addAttr = function(attr) { + attr = attr || {}; + + if (attr.name === undefined || + attr.prefix === undefined || + attr.local === undefined + ) return false; + + this.attrs = this.attrs || {}; + this.attrs[attr.name] = attr; + + return this.attrs[attr.name]; + +}; + +/** + * Iterates over all attributes. + * + * @param {Function} callback callback + * @param {Object} [context] callback context + * @return {Boolean} false if there are no any attributes + */ + JSAPI.prototype.eachAttr = function(callback, context) { + + if (!this.hasAttr()) return false; + + for (var name in this.attrs) { + callback.call(context, this.attrs[name]); + } + + return true; + +}; + +/** + * Tests whether some attribute passes the test. + * + * @param {Function} callback callback + * @param {Object} [context] callback context + * @return {Boolean} false if there are no any attributes + */ + JSAPI.prototype.someAttr = function(callback, context) { + + if (!this.hasAttr()) return false; + + for (var name in this.attrs) { + if (callback.call(context, this.attrs[name])) return true; + } + + return false; + +}; diff --git a/node_modules/svgo/lib/svgo/plugins.js b/node_modules/svgo/lib/svgo/plugins.js new file mode 100644 index 00000000..4e0308da --- /dev/null +++ b/node_modules/svgo/lib/svgo/plugins.js @@ -0,0 +1,98 @@ +'use strict'; + +/** + * Plugins engine. + * + * @module plugins + * + * @param {Object} data input data + * @param {Object} plugins plugins object from config + * @return {Object} output data + */ +module.exports = function(data, plugins) { + + plugins.forEach(function(group) { + + switch(group[0].type) { + case 'perItem': + data = perItem(data, group); + break; + case 'perItemReverse': + data = perItem(data, group, true); + break; + case 'full': + data = full(data, group); + break; + } + + }); + + return data; + +}; + +/** + * Direct or reverse per-item loop. + * + * @param {Object} data input data + * @param {Array} plugins plugins list to process + * @param {Boolean} [reverse] reverse pass? + * @return {Object} output data + */ +function perItem(data, plugins, reverse) { + + function monkeys(items) { + + items.content = items.content.filter(function(item) { + + // reverse pass + if (reverse && item.content) { + monkeys(item); + } + + // main filter + var filter = true; + + for (var i = 0; filter && i < plugins.length; i++) { + var plugin = plugins[i]; + + if (plugin.active && plugin.fn(item, plugin.params) === false) { + filter = false; + } + } + + // direct pass + if (!reverse && item.content) { + monkeys(item); + } + + return filter; + + }); + + return items; + + } + + return monkeys(data); + +} + +/** + * "Full" plugins. + * + * @param {Object} data input data + * @param {Array} plugins plugins list to process + * @return {Object} output data + */ +function full(data, plugins) { + + plugins.forEach(function(plugin) { + if (plugin.active) { + data = plugin.fn(data, plugin.params); + } + }); + + return data; + +} diff --git a/node_modules/svgo/lib/svgo/svg2js.js b/node_modules/svgo/lib/svgo/svg2js.js new file mode 100644 index 00000000..2c36900c --- /dev/null +++ b/node_modules/svgo/lib/svgo/svg2js.js @@ -0,0 +1,187 @@ +'use strict'; + +var SAX = require('sax'), + JSAPI = require('./jsAPI.js'), + entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^\']+)'|"([^\"]+)")\s*>/g; + +var config = { + strict: true, + trim: false, + normalize: true, + lowercase: true, + xmlns: true, + position: true +}; + +/** + * Convert SVG (XML) string to SVG-as-JS object. + * + * @param {String} data input data + * @param {Function} callback + */ +module.exports = function(data, callback) { + + var sax = SAX.parser(config.strict, config), + root = new JSAPI({ elem: '#document' }), + current = root, + stack = [root], + textContext = null, + parsingError = false; + + function pushToContent(content) { + + content = new JSAPI(content, current); + + (current.content = current.content || []).push(content); + + return content; + + } + + sax.ondoctype = function(doctype) { + + pushToContent({ + doctype: doctype + }); + + var subsetStart = doctype.indexOf('['), + entityMatch; + + if (subsetStart >= 0) { + entityDeclaration.lastIndex = subsetStart; + + while ((entityMatch = entityDeclaration.exec(data)) != null) { + sax.ENTITIES[entityMatch[1]] = entityMatch[2] || entityMatch[3]; + } + } + }; + + sax.onprocessinginstruction = function(data) { + + pushToContent({ + processinginstruction: data + }); + + }; + + sax.oncomment = function(comment) { + + pushToContent({ + comment: comment.trim() + }); + + }; + + sax.oncdata = function(cdata) { + + pushToContent({ + cdata: cdata + }); + + }; + + sax.onopentag = function(data) { + + var elem = { + elem: data.name, + prefix: data.prefix, + local: data.local + }; + + if (Object.keys(data.attributes).length) { + elem.attrs = {}; + + for (var name in data.attributes) { + elem.attrs[name] = { + name: name, + value: data.attributes[name].value, + prefix: data.attributes[name].prefix, + local: data.attributes[name].local + }; + } + } + + elem = pushToContent(elem); + current = elem; + + // Save info about <text> tag to prevent trimming of meaningful whitespace + if (data.name == 'text' && !data.prefix) { + textContext = current; + } + + stack.push(elem); + + }; + + sax.ontext = function(text) { + + if (/\S/.test(text) || textContext) { + + if (!textContext) + text = text.trim(); + + pushToContent({ + text: text + }); + + } + + }; + + sax.onclosetag = function() { + + var last = stack.pop(); + + // Trim text inside <text> tag. + if (last == textContext) { + trim(textContext); + textContext = null; + } + current = stack[stack.length - 1]; + + }; + + sax.onerror = function(e) { + + e.message = 'Error in parsing SVG: ' + e.message; + if (e.message.indexOf('Unexpected end') < 0) { + throw e; + } + + }; + + sax.onend = function() { + + if (!this.error) { + callback(root); + } else { + callback({ error: this.error.message }); + } + + }; + + try { + sax.write(data); + } catch (e) { + callback({ error: e.message }); + parsingError = true; + } + if (!parsingError) sax.close(); + + function trim(elem) { + if (!elem.content) return elem; + + var start = elem.content[0], + end = elem.content[elem.content.length - 1]; + + while (start && start.content && !start.text) start = start.content[0]; + if (start && start.text) start.text = start.text.replace(/^\s+/, ''); + + while (end && end.content && !end.text) end = end.content[end.content.length - 1]; + if (end && end.text) end.text = end.text.replace(/\s+$/, ''); + + return elem; + + } + +}; diff --git a/node_modules/svgo/lib/svgo/tools.js b/node_modules/svgo/lib/svgo/tools.js new file mode 100644 index 00000000..7dd33c07 --- /dev/null +++ b/node_modules/svgo/lib/svgo/tools.js @@ -0,0 +1,147 @@ +'use strict'; + +/** + * Encode plain SVG data string into Data URI string. + * + * @param {String} str input string + * @param {String} type Data URI type + * @return {String} output string + */ +exports.encodeSVGDatauri = function(str, type) { + + var prefix = 'data:image/svg+xml'; + + // base64 + if (!type || type === 'base64') { + + prefix += ';base64,'; + + str = prefix + new Buffer(str).toString('base64'); + + // URI encoded + } else if (type === 'enc') { + + str = prefix + ',' + encodeURIComponent(str); + + // unencoded + } else if (type === 'unenc') { + + str = prefix + ',' + str; + + } + + return str; + +}; + +/** + * Decode SVG Data URI string into plain SVG string. + * + * @param {string} str input string + * @return {String} output string + */ +exports.decodeSVGDatauri = function(str) { + var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/; + var match = regexp.exec(str); + + // plain string + if (!match) return str; + + var data = match[3]; + + // base64 + if (match[2]) { + + str = new Buffer(data, 'base64').toString('utf8'); + + // URI encoded + } else if (data.charAt(0) === '%') { + + str = decodeURIComponent(data); + + // unencoded + } else if (data.charAt(0) === '<') { + + str = data; + + } + + return str; +}; + +exports.intersectArrays = function(a, b) { + return a.filter(function(n) { + return b.indexOf(n) > -1; + }); +}; + +exports.cleanupOutData = function(data, params) { + + var str = '', + delimiter, + prev; + + data.forEach(function(item, i) { + + // space delimiter by default + delimiter = ' '; + + // no extra space in front of first number + if (i === 0) { + delimiter = ''; + } + + // remove floating-point numbers leading zeros + // 0.5 → .5 + // -0.5 → -.5 + if (params.leadingZero) { + item = removeLeadingZero(item); + } + + // no extra space in front of negative number or + // in front of a floating number if a previous number is floating too + if ( + params.negativeExtraSpace && + (item < 0 || + (String(item).charCodeAt(0) == 46 && prev % 1 !== 0) + ) + ) { + delimiter = ''; + } + + // save prev item value + prev = item; + + str += delimiter + item; + + }); + + return str; + +}; + +/** + * Remove floating-point numbers leading zero. + * + * @example + * 0.5 → .5 + * + * @example + * -0.5 → -.5 + * + * @param {Float} num input number + * + * @return {String} output number as string + */ +var removeLeadingZero = exports.removeLeadingZero = function(num) { + var strNum = num.toString(); + + if (0 < num && num < 1 && strNum.charCodeAt(0) == 48) { + strNum = strNum.slice(1); + } else if (-1 < num && num < 0 && strNum.charCodeAt(1) == 48) { + strNum = strNum.charAt(0) + strNum.slice(2); + } + + return strNum; + +}; diff --git a/node_modules/svgo/node_modules/.bin/csso b/node_modules/svgo/node_modules/.bin/csso new file mode 120000 index 00000000..b14445ba --- /dev/null +++ b/node_modules/svgo/node_modules/.bin/csso @@ -0,0 +1 @@ +../../../csso/bin/csso
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/.bin/js-yaml b/node_modules/svgo/node_modules/.bin/js-yaml new file mode 120000 index 00000000..9dbd010d --- /dev/null +++ b/node_modules/svgo/node_modules/.bin/js-yaml @@ -0,0 +1 @@ +../js-yaml/bin/js-yaml.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/.bin/mkdirp b/node_modules/svgo/node_modules/.bin/mkdirp new file mode 120000 index 00000000..91a5f623 --- /dev/null +++ b/node_modules/svgo/node_modules/.bin/mkdirp @@ -0,0 +1 @@ +../../../mkdirp/bin/cmd.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/esprima/.bin/esparse b/node_modules/svgo/node_modules/esprima/.bin/esparse new file mode 120000 index 00000000..88083f29 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/.bin/esparse @@ -0,0 +1 @@ +../bin/esparse.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/esprima/.bin/esvalidate b/node_modules/svgo/node_modules/esprima/.bin/esvalidate new file mode 120000 index 00000000..5f4621b4 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/.bin/esvalidate @@ -0,0 +1 @@ +../bin/esvalidate.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/esprima/ChangeLog b/node_modules/svgo/node_modules/esprima/ChangeLog new file mode 100644 index 00000000..fd687ae3 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/ChangeLog @@ -0,0 +1,174 @@ +2016-08-23: Version 2.7.3 + + * Fix tokenizer confusion with a comment (issue 1493, 1516) + +2016-02-02: Version 2.7.2 + + * Fix out-of-bound error location in an invalid string literal (issue 1457) + * Fix shorthand object destructuring defaults in variable declarations (issue 1459) + +2015-12-10: Version 2.7.1 + + * Do not allow trailing comma in a variable declaration (issue 1360) + * Fix assignment to `let` in non-strict mode (issue 1376) + * Fix missing delegate property in YieldExpression (issue 1407) + +2015-10-22: Version 2.7.0 + + * Fix the handling of semicolon in a break statement (issue 1044) + * Run the test suite with major web browsers (issue 1259, 1317) + * Allow `let` as an identifier in non-strict mode (issue 1289) + * Attach orphaned comments as `innerComments` (issue 1328) + * Add the support for token delegator (issue 1332) + +2015-09-01: Version 2.6.0 + + * Properly allow or prohibit `let` in a binding identifier/pattern (issue 1048, 1098) + * Add sourceType field for Program node (issue 1159) + * Ensure that strict mode reserved word binding throw an error (issue 1171) + * Run the test suite with Node.js and IE 11 on Windows (issue 1294) + * Allow binding pattern with no initializer in a for statement (issue 1301) + +2015-07-31: Version 2.5.0 + + * Run the test suite in a browser environment (issue 1004) + * Ensure a comma between imported default binding and named imports (issue 1046) + * Distinguish `yield` as a keyword vs an identifier (issue 1186) + * Support ES6 meta property `new.target` (issue 1203) + * Fix the syntax node for yield with expression (issue 1223) + * Fix the check of duplicated proto in property names (issue 1225) + * Fix ES6 Unicode escape in identifier name (issue 1229) + * Support ES6 IdentifierStart and IdentifierPart (issue 1232) + * Treat await as a reserved word when parsing as a module (issue 1234) + * Recognize identifier characters from Unicode SMP (issue 1244) + * Ensure that export and import can be followed by a comma (issue 1250) + * Fix yield operator precedence (issue 1262) + +2015-07-01: Version 2.4.1 + + * Fix some cases of comment attachment (issue 1071, 1175) + * Fix the handling of destructuring in function arguments (issue 1193) + * Fix invalid ranges in assignment expression (issue 1201) + +2015-06-26: Version 2.4.0 + + * Support ES6 for-of iteration (issue 1047) + * Support ES6 spread arguments (issue 1169) + * Minimize npm payload (issue 1191) + +2015-06-16: Version 2.3.0 + + * Support ES6 generator (issue 1033) + * Improve parsing of regular expressions with `u` flag (issue 1179) + +2015-04-17: Version 2.2.0 + + * Support ES6 import and export declarations (issue 1000) + * Fix line terminator before arrow not recognized as error (issue 1009) + * Support ES6 destructuring (issue 1045) + * Support ES6 template literal (issue 1074) + * Fix the handling of invalid/incomplete string escape sequences (issue 1106) + * Fix ES3 static member access restriction (issue 1120) + * Support for `super` in ES6 class (issue 1147) + +2015-03-09: Version 2.1.0 + + * Support ES6 class (issue 1001) + * Support ES6 rest parameter (issue 1011) + * Expand the location of property getter, setter, and methods (issue 1029) + * Enable TryStatement transition to a single handler (issue 1031) + * Support ES6 computed property name (issue 1037) + * Tolerate unclosed block comment (issue 1041) + * Support ES6 lexical declaration (issue 1065) + +2015-02-06: Version 2.0.0 + + * Support ES6 arrow function (issue 517) + * Support ES6 Unicode code point escape (issue 521) + * Improve the speed and accuracy of comment attachment (issue 522) + * Support ES6 default parameter (issue 519) + * Support ES6 regular expression flags (issue 557) + * Fix scanning of implicit octal literals (issue 565) + * Fix the handling of automatic semicolon insertion (issue 574) + * Support ES6 method definition (issue 620) + * Support ES6 octal integer literal (issue 621) + * Support ES6 binary integer literal (issue 622) + * Support ES6 object literal property value shorthand (issue 624) + +2015-03-03: Version 1.2.5 + + * Fix scanning of implicit octal literals (issue 565) + +2015-02-05: Version 1.2.4 + + * Fix parsing of LeftHandSideExpression in ForInStatement (issue 560) + * Fix the handling of automatic semicolon insertion (issue 574) + +2015-01-18: Version 1.2.3 + + * Fix division by this (issue 616) + +2014-05-18: Version 1.2.2 + + * Fix duplicated tokens when collecting comments (issue 537) + +2014-05-04: Version 1.2.1 + + * Ensure that Program node may still have leading comments (issue 536) + +2014-04-29: Version 1.2.0 + + * Fix semicolon handling for expression statement (issue 462, 533) + * Disallow escaped characters in regular expression flags (issue 503) + * Performance improvement for location tracking (issue 520) + * Improve the speed of comment attachment (issue 522) + +2014-03-26: Version 1.1.1 + + * Fix token handling of forward slash after an array literal (issue 512) + +2014-03-23: Version 1.1.0 + + * Optionally attach comments to the owning syntax nodes (issue 197) + * Simplify binary parsing with stack-based shift reduce (issue 352) + * Always include the raw source of literals (issue 376) + * Add optional input source information (issue 386) + * Tokenizer API for pure lexical scanning (issue 398) + * Improve the web site and its online demos (issue 337, 400, 404) + * Performance improvement for location tracking (issue 417, 424) + * Support HTML comment syntax (issue 451) + * Drop support for legacy browsers (issue 474) + +2013-08-27: Version 1.0.4 + + * Minimize the payload for packages (issue 362) + * Fix missing cases on an empty switch statement (issue 436) + * Support escaped ] in regexp literal character classes (issue 442) + * Tolerate invalid left-hand side expression (issue 130) + +2013-05-17: Version 1.0.3 + + * Variable declaration needs at least one declarator (issue 391) + * Fix benchmark's variance unit conversion (issue 397) + * IE < 9: \v should be treated as vertical tab (issue 405) + * Unary expressions should always have prefix: true (issue 418) + * Catch clause should only accept an identifier (issue 423) + * Tolerate setters without parameter (issue 426) + +2012-11-02: Version 1.0.2 + + Improvement: + + * Fix esvalidate JUnit output upon a syntax error (issue 374) + +2012-10-28: Version 1.0.1 + + Improvements: + + * esvalidate understands shebang in a Unix shell script (issue 361) + * esvalidate treats fatal parsing failure as an error (issue 361) + * Reduce Node.js package via .npmignore (issue 362) + +2012-10-22: Version 1.0.0 + + Initial release. diff --git a/node_modules/svgo/node_modules/esprima/LICENSE.BSD b/node_modules/svgo/node_modules/esprima/LICENSE.BSD new file mode 100644 index 00000000..17557ece --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/LICENSE.BSD @@ -0,0 +1,21 @@ +Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/svgo/node_modules/esprima/README.md b/node_modules/svgo/node_modules/esprima/README.md new file mode 100644 index 00000000..749454f4 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/README.md @@ -0,0 +1,27 @@ +[](https://www.npmjs.com/package/esprima) +[](https://www.npmjs.com/package/esprima) +[](https://travis-ci.org/jquery/esprima) +[](https://codecov.io/github/jquery/esprima) + +**Esprima** ([esprima.org](http://esprima.org), BSD license) is a high performance, +standard-compliant [ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm) +parser written in ECMAScript (also popularly known as +[JavaScript](https://en.wikipedia.org/wiki/JavaScript)). +Esprima is created and maintained by [Ariya Hidayat](https://twitter.com/ariyahidayat), +with the help of [many contributors](https://github.com/jquery/esprima/contributors). + +### Features + +- Full support for ECMAScript 6 ([ECMA-262](http://www.ecma-international.org/publications/standards/Ecma-262.htm)) +- Sensible [syntax tree format](https://github.com/estree/estree/blob/master/spec.md) as standardized by [ESTree project](https://github.com/estree/estree) +- Optional tracking of syntax node location (index-based and line-column) +- [Heavily tested](http://esprima.org/test/ci.html) (~1250 [unit tests](https://github.com/jquery/esprima/tree/master/test/fixtures) with [full code coverage](https://codecov.io/github/jquery/esprima)) + +Esprima serves as a **building block** for some JavaScript +language tools, from [code instrumentation](http://esprima.org/demo/functiontrace.html) +to [editor autocompletion](http://esprima.org/demo/autocomplete.html). + +Esprima runs on many popular web browsers, as well as other ECMAScript platforms such as +[Rhino](http://www.mozilla.org/rhino), [Nashorn](http://openjdk.java.net/projects/nashorn/), and [Node.js](https://npmjs.org/package/esprima). + +For more information, check the web site [esprima.org](http://esprima.org). diff --git a/node_modules/svgo/node_modules/esprima/bin/esparse.js b/node_modules/svgo/node_modules/esprima/bin/esparse.js new file mode 100755 index 00000000..98bdbf48 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/bin/esparse.js @@ -0,0 +1,126 @@ +#!/usr/bin/env node +/* + Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint sloppy:true node:true rhino:true */ + +var fs, esprima, fname, content, options, syntax; + +if (typeof require === 'function') { + fs = require('fs'); + esprima = require('esprima'); +} else if (typeof load === 'function') { + try { + load('esprima.js'); + } catch (e) { + load('../esprima.js'); + } +} + +// Shims to Node.js objects when running under Rhino. +if (typeof console === 'undefined' && typeof process === 'undefined') { + console = { log: print }; + fs = { readFileSync: readFile }; + process = { argv: arguments, exit: quit }; + process.argv.unshift('esparse.js'); + process.argv.unshift('rhino'); +} + +function showUsage() { + console.log('Usage:'); + console.log(' esparse [options] file.js'); + console.log(); + console.log('Available options:'); + console.log(); + console.log(' --comment Gather all line and block comments in an array'); + console.log(' --loc Include line-column location info for each syntax node'); + console.log(' --range Include index-based range for each syntax node'); + console.log(' --raw Display the raw value of literals'); + console.log(' --tokens List all tokens in an array'); + console.log(' --tolerant Tolerate errors on a best-effort basis (experimental)'); + console.log(' -v, --version Shows program version'); + console.log(); + process.exit(1); +} + +if (process.argv.length <= 2) { + showUsage(); +} + +options = {}; + +process.argv.splice(2).forEach(function (entry) { + + if (entry === '-h' || entry === '--help') { + showUsage(); + } else if (entry === '-v' || entry === '--version') { + console.log('ECMAScript Parser (using Esprima version', esprima.version, ')'); + console.log(); + process.exit(0); + } else if (entry === '--comment') { + options.comment = true; + } else if (entry === '--loc') { + options.loc = true; + } else if (entry === '--range') { + options.range = true; + } else if (entry === '--raw') { + options.raw = true; + } else if (entry === '--tokens') { + options.tokens = true; + } else if (entry === '--tolerant') { + options.tolerant = true; + } else if (entry.slice(0, 2) === '--') { + console.log('Error: unknown option ' + entry + '.'); + process.exit(1); + } else if (typeof fname === 'string') { + console.log('Error: more than one input file.'); + process.exit(1); + } else { + fname = entry; + } +}); + +if (typeof fname !== 'string') { + console.log('Error: no input file.'); + process.exit(1); +} + +// Special handling for regular expression literal since we need to +// convert it to a string literal, otherwise it will be decoded +// as object "{}" and the regular expression would be lost. +function adjustRegexLiteral(key, value) { + if (key === 'value' && value instanceof RegExp) { + value = value.toString(); + } + return value; +} + +try { + content = fs.readFileSync(fname, 'utf-8'); + syntax = esprima.parse(content, options); + console.log(JSON.stringify(syntax, adjustRegexLiteral, 4)); +} catch (e) { + console.log('Error: ' + e.message); + process.exit(1); +} diff --git a/node_modules/svgo/node_modules/esprima/bin/esvalidate.js b/node_modules/svgo/node_modules/esprima/bin/esvalidate.js new file mode 100755 index 00000000..f522dec2 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/bin/esvalidate.js @@ -0,0 +1,199 @@ +#!/usr/bin/env node +/* + Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint sloppy:true plusplus:true node:true rhino:true */ +/*global phantom:true */ + +var fs, system, esprima, options, fnames, count; + +if (typeof esprima === 'undefined') { + // PhantomJS can only require() relative files + if (typeof phantom === 'object') { + fs = require('fs'); + system = require('system'); + esprima = require('./esprima'); + } else if (typeof require === 'function') { + fs = require('fs'); + esprima = require('esprima'); + } else if (typeof load === 'function') { + try { + load('esprima.js'); + } catch (e) { + load('../esprima.js'); + } + } +} + +// Shims to Node.js objects when running under PhantomJS 1.7+. +if (typeof phantom === 'object') { + fs.readFileSync = fs.read; + process = { + argv: [].slice.call(system.args), + exit: phantom.exit + }; + process.argv.unshift('phantomjs'); +} + +// Shims to Node.js objects when running under Rhino. +if (typeof console === 'undefined' && typeof process === 'undefined') { + console = { log: print }; + fs = { readFileSync: readFile }; + process = { argv: arguments, exit: quit }; + process.argv.unshift('esvalidate.js'); + process.argv.unshift('rhino'); +} + +function showUsage() { + console.log('Usage:'); + console.log(' esvalidate [options] file.js'); + console.log(); + console.log('Available options:'); + console.log(); + console.log(' --format=type Set the report format, plain (default) or junit'); + console.log(' -v, --version Print program version'); + console.log(); + process.exit(1); +} + +if (process.argv.length <= 2) { + showUsage(); +} + +options = { + format: 'plain' +}; + +fnames = []; + +process.argv.splice(2).forEach(function (entry) { + + if (entry === '-h' || entry === '--help') { + showUsage(); + } else if (entry === '-v' || entry === '--version') { + console.log('ECMAScript Validator (using Esprima version', esprima.version, ')'); + console.log(); + process.exit(0); + } else if (entry.slice(0, 9) === '--format=') { + options.format = entry.slice(9); + if (options.format !== 'plain' && options.format !== 'junit') { + console.log('Error: unknown report format ' + options.format + '.'); + process.exit(1); + } + } else if (entry.slice(0, 2) === '--') { + console.log('Error: unknown option ' + entry + '.'); + process.exit(1); + } else { + fnames.push(entry); + } +}); + +if (fnames.length === 0) { + console.log('Error: no input file.'); + process.exit(1); +} + +if (options.format === 'junit') { + console.log('<?xml version="1.0" encoding="UTF-8"?>'); + console.log('<testsuites>'); +} + +count = 0; +fnames.forEach(function (fname) { + var content, timestamp, syntax, name; + try { + content = fs.readFileSync(fname, 'utf-8'); + + if (content[0] === '#' && content[1] === '!') { + content = '//' + content.substr(2, content.length); + } + + timestamp = Date.now(); + syntax = esprima.parse(content, { tolerant: true }); + + if (options.format === 'junit') { + + name = fname; + if (name.lastIndexOf('/') >= 0) { + name = name.slice(name.lastIndexOf('/') + 1); + } + + console.log('<testsuite name="' + fname + '" errors="0" ' + + ' failures="' + syntax.errors.length + '" ' + + ' tests="' + syntax.errors.length + '" ' + + ' time="' + Math.round((Date.now() - timestamp) / 1000) + + '">'); + + syntax.errors.forEach(function (error) { + var msg = error.message; + msg = msg.replace(/^Line\ [0-9]*\:\ /, ''); + console.log(' <testcase name="Line ' + error.lineNumber + ': ' + msg + '" ' + + ' time="0">'); + console.log(' <error type="SyntaxError" message="' + error.message + '">' + + error.message + '(' + name + ':' + error.lineNumber + ')' + + '</error>'); + console.log(' </testcase>'); + }); + + console.log('</testsuite>'); + + } else if (options.format === 'plain') { + + syntax.errors.forEach(function (error) { + var msg = error.message; + msg = msg.replace(/^Line\ [0-9]*\:\ /, ''); + msg = fname + ':' + error.lineNumber + ': ' + msg; + console.log(msg); + ++count; + }); + + } + } catch (e) { + ++count; + if (options.format === 'junit') { + console.log('<testsuite name="' + fname + '" errors="1" failures="0" tests="1" ' + + ' time="' + Math.round((Date.now() - timestamp) / 1000) + '">'); + console.log(' <testcase name="' + e.message + '" ' + ' time="0">'); + console.log(' <error type="ParseError" message="' + e.message + '">' + + e.message + '(' + fname + ((e.lineNumber) ? ':' + e.lineNumber : '') + + ')</error>'); + console.log(' </testcase>'); + console.log('</testsuite>'); + } else { + console.log('Error: ' + e.message); + } + } +}); + +if (options.format === 'junit') { + console.log('</testsuites>'); +} + +if (count > 0) { + process.exit(1); +} + +if (count === 0 && typeof phantom === 'object') { + process.exit(0); +} diff --git a/node_modules/svgo/node_modules/esprima/esprima.js b/node_modules/svgo/node_modules/esprima/esprima.js new file mode 100644 index 00000000..0cb0a936 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/esprima.js @@ -0,0 +1,5740 @@ +/* + Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + + /* istanbul ignore next */ + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + FnExprTokens, + Syntax, + PlaceHolders, + Messages, + Regex, + source, + strict, + index, + lineNumber, + lineStart, + hasLineTerminator, + lastIndex, + lastLineNumber, + lastLineStart, + startIndex, + startLineNumber, + startLineStart, + scanning, + length, + lookahead, + state, + extra, + isBindingElement, + isAssignmentTarget, + firstCoverInitializedNameError; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8, + RegularExpression: 9, + Template: 10 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = '<end>'; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + TokenName[Token.Template] = 'Template'; + + // A function following one of those tokens is an expression. + FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', + 'return', 'case', 'delete', 'throw', 'void', + // assignment operators + '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', + '&=', '|=', '^=', ',', + // binary/unary operators + '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', + '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', + '<=', '<', '>', '!=', '!==']; + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + AssignmentPattern: 'AssignmentPattern', + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExportAllDeclaration: 'ExportAllDeclaration', + ExportDefaultDeclaration: 'ExportDefaultDeclaration', + ExportNamedDeclaration: 'ExportNamedDeclaration', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForOfStatement: 'ForOfStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportDefaultSpecifier: 'ImportDefaultSpecifier', + ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', + ImportSpecifier: 'ImportSpecifier', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MetaProperty: 'MetaProperty', + MethodDefinition: 'MethodDefinition', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + RestElement: 'RestElement', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + Super: 'Super', + SwitchCase: 'SwitchCase', + SwitchStatement: 'SwitchStatement', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + + PlaceHolders = { + ArrowParameterPlaceHolder: 'ArrowParameterPlaceHolder' + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedTemplate: 'Unexpected quasi %0', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + InvalidLHSInForLoop: 'Invalid left-hand side in for-loop', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalReturn: 'Illegal return statement', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode', + TemplateOctalLiteral: 'Octal literals are not allowed in template strings.', + ParameterAfterRestParameter: 'Rest parameter must be last formal parameter', + DefaultRestParameter: 'Unexpected token =', + ObjectPatternAsRestParameter: 'Unexpected token {', + DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals', + ConstructorSpecialMethod: 'Class constructor may not be an accessor', + DuplicateConstructor: 'A class may only have one constructor', + StaticPrototype: 'Classes may not have static property named prototype', + MissingFromClause: 'Unexpected token', + NoAsAfterImportNamespace: 'Unexpected token', + InvalidModuleSpecifier: 'Unexpected token', + IllegalImportDeclaration: 'Unexpected token', + IllegalExportDeclaration: 'Unexpected token', + DuplicateBinding: 'Duplicate binding %0' + }; + + // See also tools/generate-unicode-regex.js. + Regex = { + // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierStart: + NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDE00-\uDE11\uDE13-\uDE2B\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDE00-\uDE2F\uDE44\uDE80-\uDEAA]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]/, + + // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierPart: + NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDD0-\uDDDA\uDE00-\uDE11\uDE13-\uDE37\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF01-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/ + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + /* istanbul ignore if */ + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function isDecimalDigit(ch) { + return (ch >= 0x30 && ch <= 0x39); // 0..9 + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + function octalToDecimal(ch) { + // \0 is not octal escape sequence + var octal = (ch !== '0'), code = '01234567'.indexOf(ch); + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + + return { + code: code, + octal: octal + }; + } + + // ECMA-262 11.2 White Space + + function isWhiteSpace(ch) { + return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || + (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); + } + + // ECMA-262 11.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); + } + + // ECMA-262 11.6 Identifier Names and Identifiers + + function fromCodePoint(cp) { + return (cp < 0x10000) ? String.fromCharCode(cp) : + String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) + + String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023)); + } + + function isIdentifierStart(ch) { + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(fromCodePoint(ch))); + } + + function isIdentifierPart(ch) { + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch >= 0x30 && ch <= 0x39) || // 0..9 + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(fromCodePoint(ch))); + } + + // ECMA-262 11.6.2.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + case 'enum': + case 'export': + case 'import': + case 'super': + return true; + default: + return false; + } + } + + function isStrictModeReservedWord(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + default: + return false; + } + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // ECMA-262 11.6.2.1 Keywords + + function isKeyword(id) { + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // ECMA-262 11.4 Comments + + function addComment(type, value, start, end, loc) { + var comment; + + assert(typeof start === 'number', 'Comment must have valid position'); + + state.lastCommentStart = start; + + comment = { + type: type, + value: value + }; + if (extra.range) { + comment.range = [start, end]; + } + if (extra.loc) { + comment.loc = loc; + } + extra.comments.push(comment); + if (extra.attachComment) { + extra.leadingComments.push(comment); + extra.trailingComments.push(comment); + } + if (extra.tokenize) { + comment.type = comment.type + 'Comment'; + if (extra.delegate) { + comment = extra.delegate(comment); + } + extra.tokens.push(comment); + } + } + + function skipSingleLineComment(offset) { + var start, loc, ch, comment; + + start = index - offset; + loc = { + start: { + line: lineNumber, + column: index - lineStart - offset + } + }; + + while (index < length) { + ch = source.charCodeAt(index); + ++index; + if (isLineTerminator(ch)) { + hasLineTerminator = true; + if (extra.comments) { + comment = source.slice(start + offset, index - 1); + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + addComment('Line', comment, start, index - 1, loc); + } + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + return; + } + } + + if (extra.comments) { + comment = source.slice(start + offset, index); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Line', comment, start, index, loc); + } + } + + function skipMultiLineComment() { + var start, loc, ch, comment; + + if (extra.comments) { + start = index - 2; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (isLineTerminator(ch)) { + if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) { + ++index; + } + hasLineTerminator = true; + ++lineNumber; + ++index; + lineStart = index; + } else if (ch === 0x2A) { + // Block comment ends with '*/'. + if (source.charCodeAt(index + 1) === 0x2F) { + ++index; + ++index; + if (extra.comments) { + comment = source.slice(start + 2, index - 2); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + } + return; + } + ++index; + } else { + ++index; + } + } + + // Ran off the end of the file - the whole thing is a comment + if (extra.comments) { + loc.end = { + line: lineNumber, + column: index - lineStart + }; + comment = source.slice(start + 2, index); + addComment('Block', comment, start, index, loc); + } + tolerateUnexpectedToken(); + } + + function skipComment() { + var ch, start; + hasLineTerminator = false; + + start = (index === 0); + while (index < length) { + ch = source.charCodeAt(index); + + if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + hasLineTerminator = true; + ++index; + if (ch === 0x0D && source.charCodeAt(index) === 0x0A) { + ++index; + } + ++lineNumber; + lineStart = index; + start = true; + } else if (ch === 0x2F) { // U+002F is '/' + ch = source.charCodeAt(index + 1); + if (ch === 0x2F) { + ++index; + ++index; + skipSingleLineComment(2); + start = true; + } else if (ch === 0x2A) { // U+002A is '*' + ++index; + ++index; + skipMultiLineComment(); + } else { + break; + } + } else if (start && ch === 0x2D) { // U+002D is '-' + // U+003E is '>' + if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) { + // '-->' is a single-line comment + index += 3; + skipSingleLineComment(3); + } else { + break; + } + } else if (ch === 0x3C) { // U+003C is '<' + if (source.slice(index + 1, index + 4) === '!--') { + ++index; // `<` + ++index; // `!` + ++index; // `-` + ++index; // `-` + skipSingleLineComment(4); + } else { + break; + } + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function scanUnicodeCodePointEscape() { + var ch, code; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwUnexpectedToken(); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwUnexpectedToken(); + } + + return fromCodePoint(code); + } + + function codePointAt(i) { + var cp, first, second; + + cp = source.charCodeAt(i); + if (cp >= 0xD800 && cp <= 0xDBFF) { + second = source.charCodeAt(i + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { + first = cp; + cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + + return cp; + } + + function getComplexIdentifier() { + var cp, ch, id; + + cp = codePointAt(index); + id = fromCodePoint(cp); + index += id.length; + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (cp === 0x5C) { + if (source.charCodeAt(index) !== 0x75) { + throwUnexpectedToken(); + } + ++index; + if (source[index] === '{') { + ++index; + ch = scanUnicodeCodePointEscape(); + } else { + ch = scanHexEscape('u'); + cp = ch.charCodeAt(0); + if (!ch || ch === '\\' || !isIdentifierStart(cp)) { + throwUnexpectedToken(); + } + } + id = ch; + } + + while (index < length) { + cp = codePointAt(index); + if (!isIdentifierPart(cp)) { + break; + } + ch = fromCodePoint(cp); + id += ch; + index += ch.length; + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (cp === 0x5C) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 0x75) { + throwUnexpectedToken(); + } + ++index; + if (source[index] === '{') { + ++index; + ch = scanUnicodeCodePointEscape(); + } else { + ch = scanHexEscape('u'); + cp = ch.charCodeAt(0); + if (!ch || ch === '\\' || !isIdentifierPart(cp)) { + throwUnexpectedToken(); + } + } + id += ch; + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 0x5C) { + // Blackslash (U+005C) marks Unicode escape sequence. + index = start; + return getComplexIdentifier(); + } else if (ch >= 0xD800 && ch < 0xDFFF) { + // Need to handle surrogate pairs. + index = start; + return getComplexIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return source.slice(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + + // Backslash (U+005C) starts an escaped character. + id = (source.charCodeAt(index) === 0x5C) ? getComplexIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + + // ECMA-262 11.7 Punctuators + + function scanPunctuator() { + var token, str; + + token = { + type: Token.Punctuator, + value: '', + lineNumber: lineNumber, + lineStart: lineStart, + start: index, + end: index + }; + + // Check for most common single-character punctuators. + str = source[index]; + switch (str) { + + case '(': + if (extra.tokenize) { + extra.openParenToken = extra.tokenValues.length; + } + ++index; + break; + + case '{': + if (extra.tokenize) { + extra.openCurlyToken = extra.tokenValues.length; + } + state.curlyStack.push('{'); + ++index; + break; + + case '.': + ++index; + if (source[index] === '.' && source[index + 1] === '.') { + // Spread operator: ... + index += 2; + str = '...'; + } + break; + + case '}': + ++index; + state.curlyStack.pop(); + break; + case ')': + case ';': + case ',': + case '[': + case ']': + case ':': + case '?': + case '~': + ++index; + break; + + default: + // 4-character punctuator. + str = source.substr(index, 4); + if (str === '>>>=') { + index += 4; + } else { + + // 3-character punctuators. + str = str.substr(0, 3); + if (str === '===' || str === '!==' || str === '>>>' || + str === '<<=' || str === '>>=') { + index += 3; + } else { + + // 2-character punctuators. + str = str.substr(0, 2); + if (str === '&&' || str === '||' || str === '==' || str === '!=' || + str === '+=' || str === '-=' || str === '*=' || str === '/=' || + str === '++' || str === '--' || str === '<<' || str === '>>' || + str === '&=' || str === '|=' || str === '^=' || str === '%=' || + str === '<=' || str === '>=' || str === '=>') { + index += 2; + } else { + + // 1-character punctuators. + str = source[index]; + if ('<>=!+-*%&|^/'.indexOf(str) >= 0) { + ++index; + } + } + } + } + } + + if (index === token.start) { + throwUnexpectedToken(); + } + + token.end = index; + token.value = str; + return token; + } + + // ECMA-262 11.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + throwUnexpectedToken(); + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwUnexpectedToken(); + } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanBinaryLiteral(start) { + var ch, number; + + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwUnexpectedToken(); + } + + if (index < length) { + ch = source.charCodeAt(index); + /* istanbul ignore else */ + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwUnexpectedToken(); + } + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (!octal && number.length === 0) { + // only 0o or 0O + throwUnexpectedToken(); + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwUnexpectedToken(); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function isImplicitOctalLiteral() { + var i, ch; + + // Implicit octal, unless there is a non-octal digit. + // (Annex B.1.1 on Numeric Literals) + for (i = index + 1; i < length; ++i) { + ch = source[i]; + if (ch === '8' || ch === '9') { + return false; + } + if (!isOctalDigit(ch)) { + return true; + } + } + + return true; + } + + function scanNumericLiteral() { + var number, start, ch; + + ch = source[index]; + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + ++index; + return scanHexLiteral(start); + } + if (ch === 'b' || ch === 'B') { + ++index; + return scanBinaryLiteral(start); + } + if (ch === 'o' || ch === 'O') { + return scanOctalLiteral(ch, start); + } + + if (isOctalDigit(ch)) { + if (isImplicitOctalLiteral()) { + return scanOctalLiteral(ch, start); + } + } + } + + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === '.') { + number += source[index++]; + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + } else { + throwUnexpectedToken(); + } + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwUnexpectedToken(); + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // ECMA-262 11.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, unescaped, octToDec, octal = false; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); + } else { + unescaped = scanHexEscape(ch); + if (!unescaped) { + throw throwUnexpectedToken(); + } + str += unescaped; + } + break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + case '8': + case '9': + str += ch; + tolerateUnexpectedToken(); + break; + + default: + if (isOctalDigit(ch)) { + octToDec = octalToDecimal(ch); + + octal = octToDec.octal || octal; + str += String.fromCharCode(octToDec.code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + lineStart = index; + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + index = start; + throwUnexpectedToken(); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + lineNumber: startLineNumber, + lineStart: startLineStart, + start: start, + end: index + }; + } + + // ECMA-262 11.8.6 Template Literal Lexical Components + + function scanTemplate() { + var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped; + + terminated = false; + tail = false; + start = index; + head = (source[index] === '`'); + rawOffset = 2; + + ++index; + + while (index < length) { + ch = source[index++]; + if (ch === '`') { + rawOffset = 1; + tail = true; + terminated = true; + break; + } else if (ch === '$') { + if (source[index] === '{') { + state.curlyStack.push('${'); + ++index; + terminated = true; + break; + } + cooked += ch; + } else if (ch === '\\') { + ch = source[index++]; + if (!isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + cooked += '\n'; + break; + case 'r': + cooked += '\r'; + break; + case 't': + cooked += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + cooked += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + cooked += unescaped; + } else { + index = restore; + cooked += ch; + } + } + break; + case 'b': + cooked += '\b'; + break; + case 'f': + cooked += '\f'; + break; + case 'v': + cooked += '\v'; + break; + + default: + if (ch === '0') { + if (isDecimalDigit(source.charCodeAt(index))) { + // Illegal: \01 \02 and so on + throwError(Messages.TemplateOctalLiteral); + } + cooked += '\0'; + } else if (isOctalDigit(ch)) { + // Illegal: \1 \2 + throwError(Messages.TemplateOctalLiteral); + } else { + cooked += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + lineStart = index; + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + lineStart = index; + cooked += '\n'; + } else { + cooked += ch; + } + } + + if (!terminated) { + throwUnexpectedToken(); + } + + if (!head) { + state.curlyStack.pop(); + } + + return { + type: Token.Template, + value: { + cooked: cooked, + raw: source.slice(start + 1, index - rawOffset) + }, + head: head, + tail: tail, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // ECMA-262 11.8.5 Regular Expression Literals + + function testRegExp(pattern, flags) { + // The BMP character to use as a replacement for astral symbols when + // translating an ES6 "u"-flagged pattern to an ES5-compatible + // approximation. + // Note: replacing with '\uFFFF' enables false positives in unlikely + // scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid + // pattern that would not be detected by this substitution. + var astralSubstitute = '\uFFFF', + tmp = pattern; + + if (flags.indexOf('u') >= 0) { + tmp = tmp + // Replace every Unicode escape sequence with the equivalent + // BMP character or a constant ASCII code point in the case of + // astral symbols. (See the above note on `astralSubstitute` + // for more information.) + .replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function ($0, $1, $2) { + var codePoint = parseInt($1 || $2, 16); + if (codePoint > 0x10FFFF) { + throwUnexpectedToken(null, Messages.InvalidRegExp); + } + if (codePoint <= 0xFFFF) { + return String.fromCharCode(codePoint); + } + return astralSubstitute; + }) + // Replace each paired surrogate with a single ASCII symbol to + // avoid throwing on regular expressions that are only valid in + // combination with the "u" flag. + .replace( + /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + astralSubstitute + ); + } + + // First, detect invalid regular expressions. + try { + RegExp(tmp); + } catch (e) { + throwUnexpectedToken(null, Messages.InvalidRegExp); + } + + // Return a regular expression object for this pattern-flag pair, or + // `null` in case the current environment doesn't support the flags it + // uses. + try { + return new RegExp(pattern, flags); + } catch (exception) { + /* istanbul ignore next */ + return null; + } + } + + function scanRegExpBody() { + var ch, str, classMarker, terminated, body; + + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + classMarker = false; + terminated = false; + while (index < length) { + ch = source[index++]; + str += ch; + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch.charCodeAt(0))) { + throwUnexpectedToken(null, Messages.UnterminatedRegExp); + } + str += ch; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwUnexpectedToken(null, Messages.UnterminatedRegExp); + } else if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } + } + } + + if (!terminated) { + throwUnexpectedToken(null, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + body = str.substr(1, str.length - 2); + return { + value: body, + literal: str + }; + } + + function scanRegExpFlags() { + var ch, str, flags, restore; + + str = ''; + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch.charCodeAt(0))) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + tolerateUnexpectedToken(); + } else { + str += '\\'; + tolerateUnexpectedToken(); + } + } else { + flags += ch; + str += ch; + } + } + + return { + value: flags, + literal: str + }; + } + + function scanRegExp() { + var start, body, flags, value; + scanning = true; + + lookahead = null; + skipComment(); + start = index; + + body = scanRegExpBody(); + flags = scanRegExpFlags(); + value = testRegExp(body.value, flags.value); + scanning = false; + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + regex: { + pattern: body.value, + flags: flags.value + }, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + return { + literal: body.literal + flags.literal, + value: value, + regex: { + pattern: body.value, + flags: flags.value + }, + start: start, + end: index + }; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = scanRegExp(); + + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + /* istanbul ignore next */ + if (!extra.tokenize) { + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + regex: regex.regex, + range: [pos, index], + loc: loc + }); + } + + return regex; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + + function advanceSlash() { + var regex, previous, check; + + function testKeyword(value) { + return value && (value.length > 1) && (value[0] >= 'a') && (value[0] <= 'z'); + } + + previous = extra.tokenValues[extra.tokenValues.length - 1]; + regex = (previous !== null); + + switch (previous) { + case 'this': + case ']': + regex = false; + break; + + case ')': + check = extra.tokenValues[extra.openParenToken - 1]; + regex = (check === 'if' || check === 'while' || check === 'for' || check === 'with'); + break; + + case '}': + // Dividing a function by anything makes little sense, + // but we have to check for that. + regex = false; + if (testKeyword(extra.tokenValues[extra.openCurlyToken - 3])) { + // Anonymous function, e.g. function(){} /42 + check = extra.tokenValues[extra.openCurlyToken - 4]; + regex = check ? (FnExprTokens.indexOf(check) < 0) : false; + } else if (testKeyword(extra.tokenValues[extra.openCurlyToken - 4])) { + // Named function, e.g. function f(){} /42/ + check = extra.tokenValues[extra.openCurlyToken - 5]; + regex = check ? (FnExprTokens.indexOf(check) < 0) : true; + } + } + + return regex ? collectRegex() : scanPunctuator(); + } + + function advance() { + var cp, token; + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + start: index, + end: index + }; + } + + cp = source.charCodeAt(index); + + if (isIdentifierStart(cp)) { + token = scanIdentifier(); + if (strict && isStrictModeReservedWord(token.value)) { + token.type = Token.Keyword; + } + return token; + } + + // Very common: ( and ) and ; + if (cp === 0x28 || cp === 0x29 || cp === 0x3B) { + return scanPunctuator(); + } + + // String literal starts with single quote (U+0027) or double quote (U+0022). + if (cp === 0x27 || cp === 0x22) { + return scanStringLiteral(); + } + + // Dot (.) U+002E can also start a floating-point number, hence the need + // to check the next character. + if (cp === 0x2E) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(cp)) { + return scanNumericLiteral(); + } + + // Slash (/) U+002F can also start a regex. + if (extra.tokenize && cp === 0x2F) { + return advanceSlash(); + } + + // Template literals start with ` (U+0060) for template head + // or } (U+007D) for template middle or template tail. + if (cp === 0x60 || (cp === 0x7D && state.curlyStack[state.curlyStack.length - 1] === '${')) { + return scanTemplate(); + } + + // Possible identifier start in a surrogate pair. + if (cp >= 0xD800 && cp < 0xDFFF) { + cp = codePointAt(index); + if (isIdentifierStart(cp)) { + return scanIdentifier(); + } + } + + return scanPunctuator(); + } + + function collectToken() { + var loc, token, value, entry; + + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + value = source.slice(token.start, token.end); + entry = { + type: TokenName[token.type], + value: value, + range: [token.start, token.end], + loc: loc + }; + if (token.regex) { + entry.regex = { + pattern: token.regex.pattern, + flags: token.regex.flags + }; + } + if (extra.tokenValues) { + extra.tokenValues.push((entry.type === 'Punctuator' || entry.type === 'Keyword') ? entry.value : null); + } + if (extra.tokenize) { + if (!extra.range) { + delete entry.range; + } + if (!extra.loc) { + delete entry.loc; + } + if (extra.delegate) { + entry = extra.delegate(entry); + } + } + extra.tokens.push(entry); + } + + return token; + } + + function lex() { + var token; + scanning = true; + + lastIndex = index; + lastLineNumber = lineNumber; + lastLineStart = lineStart; + + skipComment(); + + token = lookahead; + + startIndex = index; + startLineNumber = lineNumber; + startLineStart = lineStart; + + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + scanning = false; + return token; + } + + function peek() { + scanning = true; + + skipComment(); + + lastIndex = index; + lastLineNumber = lineNumber; + lastLineStart = lineStart; + + startIndex = index; + startLineNumber = lineNumber; + startLineStart = lineStart; + + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + scanning = false; + } + + function Position() { + this.line = startLineNumber; + this.column = startIndex - startLineStart; + } + + function SourceLocation() { + this.start = new Position(); + this.end = null; + } + + function WrappingSourceLocation(startToken) { + this.start = { + line: startToken.lineNumber, + column: startToken.start - startToken.lineStart + }; + this.end = null; + } + + function Node() { + if (extra.range) { + this.range = [startIndex, 0]; + } + if (extra.loc) { + this.loc = new SourceLocation(); + } + } + + function WrappingNode(startToken) { + if (extra.range) { + this.range = [startToken.start, 0]; + } + if (extra.loc) { + this.loc = new WrappingSourceLocation(startToken); + } + } + + WrappingNode.prototype = Node.prototype = { + + processComment: function () { + var lastChild, + innerComments, + leadingComments, + trailingComments, + bottomRight = extra.bottomRightStack, + i, + comment, + last = bottomRight[bottomRight.length - 1]; + + if (this.type === Syntax.Program) { + if (this.body.length > 0) { + return; + } + } + /** + * patch innnerComments for properties empty block + * `function a() {/** comments **\/}` + */ + + if (this.type === Syntax.BlockStatement && this.body.length === 0) { + innerComments = []; + for (i = extra.leadingComments.length - 1; i >= 0; --i) { + comment = extra.leadingComments[i]; + if (this.range[1] >= comment.range[1]) { + innerComments.unshift(comment); + extra.leadingComments.splice(i, 1); + extra.trailingComments.splice(i, 1); + } + } + if (innerComments.length) { + this.innerComments = innerComments; + //bottomRight.push(this); + return; + } + } + + if (extra.trailingComments.length > 0) { + trailingComments = []; + for (i = extra.trailingComments.length - 1; i >= 0; --i) { + comment = extra.trailingComments[i]; + if (comment.range[0] >= this.range[1]) { + trailingComments.unshift(comment); + extra.trailingComments.splice(i, 1); + } + } + extra.trailingComments = []; + } else { + if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) { + trailingComments = last.trailingComments; + delete last.trailingComments; + } + } + + // Eating the stack. + while (last && last.range[0] >= this.range[0]) { + lastChild = bottomRight.pop(); + last = bottomRight[bottomRight.length - 1]; + } + + if (lastChild) { + if (lastChild.leadingComments) { + leadingComments = []; + for (i = lastChild.leadingComments.length - 1; i >= 0; --i) { + comment = lastChild.leadingComments[i]; + if (comment.range[1] <= this.range[0]) { + leadingComments.unshift(comment); + lastChild.leadingComments.splice(i, 1); + } + } + + if (!lastChild.leadingComments.length) { + lastChild.leadingComments = undefined; + } + } + } else if (extra.leadingComments.length > 0) { + leadingComments = []; + for (i = extra.leadingComments.length - 1; i >= 0; --i) { + comment = extra.leadingComments[i]; + if (comment.range[1] <= this.range[0]) { + leadingComments.unshift(comment); + extra.leadingComments.splice(i, 1); + } + } + } + + + if (leadingComments && leadingComments.length > 0) { + this.leadingComments = leadingComments; + } + if (trailingComments && trailingComments.length > 0) { + this.trailingComments = trailingComments; + } + + bottomRight.push(this); + }, + + finish: function () { + if (extra.range) { + this.range[1] = lastIndex; + } + if (extra.loc) { + this.loc.end = { + line: lastLineNumber, + column: lastIndex - lastLineStart + }; + if (extra.source) { + this.loc.source = extra.source; + } + } + + if (extra.attachComment) { + this.processComment(); + } + }, + + finishArrayExpression: function (elements) { + this.type = Syntax.ArrayExpression; + this.elements = elements; + this.finish(); + return this; + }, + + finishArrayPattern: function (elements) { + this.type = Syntax.ArrayPattern; + this.elements = elements; + this.finish(); + return this; + }, + + finishArrowFunctionExpression: function (params, defaults, body, expression) { + this.type = Syntax.ArrowFunctionExpression; + this.id = null; + this.params = params; + this.defaults = defaults; + this.body = body; + this.generator = false; + this.expression = expression; + this.finish(); + return this; + }, + + finishAssignmentExpression: function (operator, left, right) { + this.type = Syntax.AssignmentExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; + }, + + finishAssignmentPattern: function (left, right) { + this.type = Syntax.AssignmentPattern; + this.left = left; + this.right = right; + this.finish(); + return this; + }, + + finishBinaryExpression: function (operator, left, right) { + this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; + }, + + finishBlockStatement: function (body) { + this.type = Syntax.BlockStatement; + this.body = body; + this.finish(); + return this; + }, + + finishBreakStatement: function (label) { + this.type = Syntax.BreakStatement; + this.label = label; + this.finish(); + return this; + }, + + finishCallExpression: function (callee, args) { + this.type = Syntax.CallExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; + }, + + finishCatchClause: function (param, body) { + this.type = Syntax.CatchClause; + this.param = param; + this.body = body; + this.finish(); + return this; + }, + + finishClassBody: function (body) { + this.type = Syntax.ClassBody; + this.body = body; + this.finish(); + return this; + }, + + finishClassDeclaration: function (id, superClass, body) { + this.type = Syntax.ClassDeclaration; + this.id = id; + this.superClass = superClass; + this.body = body; + this.finish(); + return this; + }, + + finishClassExpression: function (id, superClass, body) { + this.type = Syntax.ClassExpression; + this.id = id; + this.superClass = superClass; + this.body = body; + this.finish(); + return this; + }, + + finishConditionalExpression: function (test, consequent, alternate) { + this.type = Syntax.ConditionalExpression; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; + }, + + finishContinueStatement: function (label) { + this.type = Syntax.ContinueStatement; + this.label = label; + this.finish(); + return this; + }, + + finishDebuggerStatement: function () { + this.type = Syntax.DebuggerStatement; + this.finish(); + return this; + }, + + finishDoWhileStatement: function (body, test) { + this.type = Syntax.DoWhileStatement; + this.body = body; + this.test = test; + this.finish(); + return this; + }, + + finishEmptyStatement: function () { + this.type = Syntax.EmptyStatement; + this.finish(); + return this; + }, + + finishExpressionStatement: function (expression) { + this.type = Syntax.ExpressionStatement; + this.expression = expression; + this.finish(); + return this; + }, + + finishForStatement: function (init, test, update, body) { + this.type = Syntax.ForStatement; + this.init = init; + this.test = test; + this.update = update; + this.body = body; + this.finish(); + return this; + }, + + finishForOfStatement: function (left, right, body) { + this.type = Syntax.ForOfStatement; + this.left = left; + this.right = right; + this.body = body; + this.finish(); + return this; + }, + + finishForInStatement: function (left, right, body) { + this.type = Syntax.ForInStatement; + this.left = left; + this.right = right; + this.body = body; + this.each = false; + this.finish(); + return this; + }, + + finishFunctionDeclaration: function (id, params, defaults, body, generator) { + this.type = Syntax.FunctionDeclaration; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.generator = generator; + this.expression = false; + this.finish(); + return this; + }, + + finishFunctionExpression: function (id, params, defaults, body, generator) { + this.type = Syntax.FunctionExpression; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.generator = generator; + this.expression = false; + this.finish(); + return this; + }, + + finishIdentifier: function (name) { + this.type = Syntax.Identifier; + this.name = name; + this.finish(); + return this; + }, + + finishIfStatement: function (test, consequent, alternate) { + this.type = Syntax.IfStatement; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; + }, + + finishLabeledStatement: function (label, body) { + this.type = Syntax.LabeledStatement; + this.label = label; + this.body = body; + this.finish(); + return this; + }, + + finishLiteral: function (token) { + this.type = Syntax.Literal; + this.value = token.value; + this.raw = source.slice(token.start, token.end); + if (token.regex) { + this.regex = token.regex; + } + this.finish(); + return this; + }, + + finishMemberExpression: function (accessor, object, property) { + this.type = Syntax.MemberExpression; + this.computed = accessor === '['; + this.object = object; + this.property = property; + this.finish(); + return this; + }, + + finishMetaProperty: function (meta, property) { + this.type = Syntax.MetaProperty; + this.meta = meta; + this.property = property; + this.finish(); + return this; + }, + + finishNewExpression: function (callee, args) { + this.type = Syntax.NewExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; + }, + + finishObjectExpression: function (properties) { + this.type = Syntax.ObjectExpression; + this.properties = properties; + this.finish(); + return this; + }, + + finishObjectPattern: function (properties) { + this.type = Syntax.ObjectPattern; + this.properties = properties; + this.finish(); + return this; + }, + + finishPostfixExpression: function (operator, argument) { + this.type = Syntax.UpdateExpression; + this.operator = operator; + this.argument = argument; + this.prefix = false; + this.finish(); + return this; + }, + + finishProgram: function (body, sourceType) { + this.type = Syntax.Program; + this.body = body; + this.sourceType = sourceType; + this.finish(); + return this; + }, + + finishProperty: function (kind, key, computed, value, method, shorthand) { + this.type = Syntax.Property; + this.key = key; + this.computed = computed; + this.value = value; + this.kind = kind; + this.method = method; + this.shorthand = shorthand; + this.finish(); + return this; + }, + + finishRestElement: function (argument) { + this.type = Syntax.RestElement; + this.argument = argument; + this.finish(); + return this; + }, + + finishReturnStatement: function (argument) { + this.type = Syntax.ReturnStatement; + this.argument = argument; + this.finish(); + return this; + }, + + finishSequenceExpression: function (expressions) { + this.type = Syntax.SequenceExpression; + this.expressions = expressions; + this.finish(); + return this; + }, + + finishSpreadElement: function (argument) { + this.type = Syntax.SpreadElement; + this.argument = argument; + this.finish(); + return this; + }, + + finishSwitchCase: function (test, consequent) { + this.type = Syntax.SwitchCase; + this.test = test; + this.consequent = consequent; + this.finish(); + return this; + }, + + finishSuper: function () { + this.type = Syntax.Super; + this.finish(); + return this; + }, + + finishSwitchStatement: function (discriminant, cases) { + this.type = Syntax.SwitchStatement; + this.discriminant = discriminant; + this.cases = cases; + this.finish(); + return this; + }, + + finishTaggedTemplateExpression: function (tag, quasi) { + this.type = Syntax.TaggedTemplateExpression; + this.tag = tag; + this.quasi = quasi; + this.finish(); + return this; + }, + + finishTemplateElement: function (value, tail) { + this.type = Syntax.TemplateElement; + this.value = value; + this.tail = tail; + this.finish(); + return this; + }, + + finishTemplateLiteral: function (quasis, expressions) { + this.type = Syntax.TemplateLiteral; + this.quasis = quasis; + this.expressions = expressions; + this.finish(); + return this; + }, + + finishThisExpression: function () { + this.type = Syntax.ThisExpression; + this.finish(); + return this; + }, + + finishThrowStatement: function (argument) { + this.type = Syntax.ThrowStatement; + this.argument = argument; + this.finish(); + return this; + }, + + finishTryStatement: function (block, handler, finalizer) { + this.type = Syntax.TryStatement; + this.block = block; + this.guardedHandlers = []; + this.handlers = handler ? [handler] : []; + this.handler = handler; + this.finalizer = finalizer; + this.finish(); + return this; + }, + + finishUnaryExpression: function (operator, argument) { + this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression; + this.operator = operator; + this.argument = argument; + this.prefix = true; + this.finish(); + return this; + }, + + finishVariableDeclaration: function (declarations) { + this.type = Syntax.VariableDeclaration; + this.declarations = declarations; + this.kind = 'var'; + this.finish(); + return this; + }, + + finishLexicalDeclaration: function (declarations, kind) { + this.type = Syntax.VariableDeclaration; + this.declarations = declarations; + this.kind = kind; + this.finish(); + return this; + }, + + finishVariableDeclarator: function (id, init) { + this.type = Syntax.VariableDeclarator; + this.id = id; + this.init = init; + this.finish(); + return this; + }, + + finishWhileStatement: function (test, body) { + this.type = Syntax.WhileStatement; + this.test = test; + this.body = body; + this.finish(); + return this; + }, + + finishWithStatement: function (object, body) { + this.type = Syntax.WithStatement; + this.object = object; + this.body = body; + this.finish(); + return this; + }, + + finishExportSpecifier: function (local, exported) { + this.type = Syntax.ExportSpecifier; + this.exported = exported || local; + this.local = local; + this.finish(); + return this; + }, + + finishImportDefaultSpecifier: function (local) { + this.type = Syntax.ImportDefaultSpecifier; + this.local = local; + this.finish(); + return this; + }, + + finishImportNamespaceSpecifier: function (local) { + this.type = Syntax.ImportNamespaceSpecifier; + this.local = local; + this.finish(); + return this; + }, + + finishExportNamedDeclaration: function (declaration, specifiers, src) { + this.type = Syntax.ExportNamedDeclaration; + this.declaration = declaration; + this.specifiers = specifiers; + this.source = src; + this.finish(); + return this; + }, + + finishExportDefaultDeclaration: function (declaration) { + this.type = Syntax.ExportDefaultDeclaration; + this.declaration = declaration; + this.finish(); + return this; + }, + + finishExportAllDeclaration: function (src) { + this.type = Syntax.ExportAllDeclaration; + this.source = src; + this.finish(); + return this; + }, + + finishImportSpecifier: function (local, imported) { + this.type = Syntax.ImportSpecifier; + this.local = local || imported; + this.imported = imported; + this.finish(); + return this; + }, + + finishImportDeclaration: function (specifiers, src) { + this.type = Syntax.ImportDeclaration; + this.specifiers = specifiers; + this.source = src; + this.finish(); + return this; + }, + + finishYieldExpression: function (argument, delegate) { + this.type = Syntax.YieldExpression; + this.argument = argument; + this.delegate = delegate; + this.finish(); + return this; + } + }; + + + function recordError(error) { + var e, existing; + + for (e = 0; e < extra.errors.length; e++) { + existing = extra.errors[e]; + // Prevent duplicated error. + /* istanbul ignore next */ + if (existing.index === error.index && existing.message === error.message) { + return; + } + } + + extra.errors.push(error); + } + + function constructError(msg, column) { + var error = new Error(msg); + try { + throw error; + } catch (base) { + /* istanbul ignore else */ + if (Object.create && Object.defineProperty) { + error = Object.create(base); + Object.defineProperty(error, 'column', { value: column }); + } + } finally { + return error; + } + } + + function createError(line, pos, description) { + var msg, column, error; + + msg = 'Line ' + line + ': ' + description; + column = pos - (scanning ? lineStart : lastLineStart) + 1; + error = constructError(msg, column); + error.lineNumber = line; + error.description = description; + error.index = pos; + return error; + } + + // Throw an exception + + function throwError(messageFormat) { + var args, msg; + + args = Array.prototype.slice.call(arguments, 1); + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; + } + ); + + throw createError(lastLineNumber, lastIndex, msg); + } + + function tolerateError(messageFormat) { + var args, msg, error; + + args = Array.prototype.slice.call(arguments, 1); + /* istanbul ignore next */ + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; + } + ); + + error = createError(lineNumber, lastIndex, msg); + if (extra.errors) { + recordError(error); + } else { + throw error; + } + } + + // Throw an exception because of the token. + + function unexpectedTokenError(token, message) { + var value, msg = message || Messages.UnexpectedToken; + + if (token) { + if (!message) { + msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS : + (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier : + (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber : + (token.type === Token.StringLiteral) ? Messages.UnexpectedString : + (token.type === Token.Template) ? Messages.UnexpectedTemplate : + Messages.UnexpectedToken; + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + msg = Messages.UnexpectedReserved; + } else if (strict && isStrictModeReservedWord(token.value)) { + msg = Messages.StrictReservedWord; + } + } + } + + value = (token.type === Token.Template) ? token.value.raw : token.value; + } else { + value = 'ILLEGAL'; + } + + msg = msg.replace('%0', value); + + return (token && typeof token.lineNumber === 'number') ? + createError(token.lineNumber, token.start, msg) : + createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg); + } + + function throwUnexpectedToken(token, message) { + throw unexpectedTokenError(token, message); + } + + function tolerateUnexpectedToken(token, message) { + var error = unexpectedTokenError(token, message); + if (extra.errors) { + recordError(error); + } else { + throw error; + } + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpectedToken(token); + } + } + + /** + * @name expectCommaSeparator + * @description Quietly expect a comma when in tolerant mode, otherwise delegates + * to <code>expect(value)</code> + * @since 2.0 + */ + function expectCommaSeparator() { + var token; + + if (extra.errors) { + token = lookahead; + if (token.type === Token.Punctuator && token.value === ',') { + lex(); + } else if (token.type === Token.Punctuator && token.value === ';') { + lex(); + tolerateUnexpectedToken(token); + } else { + tolerateUnexpectedToken(token, Messages.UnexpectedToken); + } + } else { + expect(','); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpectedToken(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + // Return true if the next token matches the specified contextual keyword + // (where an identifier is sometimes a keyword depending on the context) + + function matchContextualKeyword(keyword) { + return lookahead.type === Token.Identifier && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(startIndex) === 0x3B || match(';')) { + lex(); + return; + } + + if (hasLineTerminator) { + return; + } + + // FIXME(ikarienator): this is seemingly an issue in the previous location info convention. + lastIndex = startIndex; + lastLineNumber = startLineNumber; + lastLineStart = startLineStart; + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpectedToken(lookahead); + } + } + + // Cover grammar support. + // + // When an assignment expression position starts with an left parenthesis, the determination of the type + // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead) + // or the first comma. This situation also defers the determination of all the expressions nested in the pair. + // + // There are three productions that can be parsed in a parentheses pair that needs to be determined + // after the outermost pair is closed. They are: + // + // 1. AssignmentExpression + // 2. BindingElements + // 3. AssignmentTargets + // + // In order to avoid exponential backtracking, we use two flags to denote if the production can be + // binding element or assignment target. + // + // The three productions have the relationship: + // + // BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression + // + // with a single exception that CoverInitializedName when used directly in an Expression, generates + // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the + // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair. + // + // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not + // effect the current flags. This means the production the parser parses is only used as an expression. Therefore + // the CoverInitializedName check is conducted. + // + // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates + // the flags outside of the parser. This means the production the parser parses is used as a part of a potential + // pattern. The CoverInitializedName check is deferred. + function isolateCoverGrammar(parser) { + var oldIsBindingElement = isBindingElement, + oldIsAssignmentTarget = isAssignmentTarget, + oldFirstCoverInitializedNameError = firstCoverInitializedNameError, + result; + isBindingElement = true; + isAssignmentTarget = true; + firstCoverInitializedNameError = null; + result = parser(); + if (firstCoverInitializedNameError !== null) { + throwUnexpectedToken(firstCoverInitializedNameError); + } + isBindingElement = oldIsBindingElement; + isAssignmentTarget = oldIsAssignmentTarget; + firstCoverInitializedNameError = oldFirstCoverInitializedNameError; + return result; + } + + function inheritCoverGrammar(parser) { + var oldIsBindingElement = isBindingElement, + oldIsAssignmentTarget = isAssignmentTarget, + oldFirstCoverInitializedNameError = firstCoverInitializedNameError, + result; + isBindingElement = true; + isAssignmentTarget = true; + firstCoverInitializedNameError = null; + result = parser(); + isBindingElement = isBindingElement && oldIsBindingElement; + isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget; + firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError; + return result; + } + + // ECMA-262 13.3.3 Destructuring Binding Patterns + + function parseArrayPattern(params, kind) { + var node = new Node(), elements = [], rest, restNode; + expect('['); + + while (!match(']')) { + if (match(',')) { + lex(); + elements.push(null); + } else { + if (match('...')) { + restNode = new Node(); + lex(); + params.push(lookahead); + rest = parseVariableIdentifier(kind); + elements.push(restNode.finishRestElement(rest)); + break; + } else { + elements.push(parsePatternWithDefault(params, kind)); + } + if (!match(']')) { + expect(','); + } + } + + } + + expect(']'); + + return node.finishArrayPattern(elements); + } + + function parsePropertyPattern(params, kind) { + var node = new Node(), key, keyToken, computed = match('['), init; + if (lookahead.type === Token.Identifier) { + keyToken = lookahead; + key = parseVariableIdentifier(); + if (match('=')) { + params.push(keyToken); + lex(); + init = parseAssignmentExpression(); + + return node.finishProperty( + 'init', key, false, + new WrappingNode(keyToken).finishAssignmentPattern(key, init), false, true); + } else if (!match(':')) { + params.push(keyToken); + return node.finishProperty('init', key, false, key, false, true); + } + } else { + key = parseObjectPropertyKey(); + } + expect(':'); + init = parsePatternWithDefault(params, kind); + return node.finishProperty('init', key, computed, init, false, false); + } + + function parseObjectPattern(params, kind) { + var node = new Node(), properties = []; + + expect('{'); + + while (!match('}')) { + properties.push(parsePropertyPattern(params, kind)); + if (!match('}')) { + expect(','); + } + } + + lex(); + + return node.finishObjectPattern(properties); + } + + function parsePattern(params, kind) { + if (match('[')) { + return parseArrayPattern(params, kind); + } else if (match('{')) { + return parseObjectPattern(params, kind); + } else if (matchKeyword('let')) { + if (kind === 'const' || kind === 'let') { + tolerateUnexpectedToken(lookahead, Messages.UnexpectedToken); + } + } + + params.push(lookahead); + return parseVariableIdentifier(kind); + } + + function parsePatternWithDefault(params, kind) { + var startToken = lookahead, pattern, previousAllowYield, right; + pattern = parsePattern(params, kind); + if (match('=')) { + lex(); + previousAllowYield = state.allowYield; + state.allowYield = true; + right = isolateCoverGrammar(parseAssignmentExpression); + state.allowYield = previousAllowYield; + pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right); + } + return pattern; + } + + // ECMA-262 12.2.5 Array Initializer + + function parseArrayInitializer() { + var elements = [], node = new Node(), restSpread; + + expect('['); + + while (!match(']')) { + if (match(',')) { + lex(); + elements.push(null); + } else if (match('...')) { + restSpread = new Node(); + lex(); + restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression)); + + if (!match(']')) { + isAssignmentTarget = isBindingElement = false; + expect(','); + } + elements.push(restSpread); + } else { + elements.push(inheritCoverGrammar(parseAssignmentExpression)); + + if (!match(']')) { + expect(','); + } + } + } + + lex(); + + return node.finishArrayExpression(elements); + } + + // ECMA-262 12.2.6 Object Initializer + + function parsePropertyFunction(node, paramInfo, isGenerator) { + var previousStrict, body; + + isAssignmentTarget = isBindingElement = false; + + previousStrict = strict; + body = isolateCoverGrammar(parseFunctionSourceElements); + + if (strict && paramInfo.firstRestricted) { + tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message); + } + if (strict && paramInfo.stricted) { + tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message); + } + + strict = previousStrict; + return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body, isGenerator); + } + + function parsePropertyMethodFunction() { + var params, method, node = new Node(), + previousAllowYield = state.allowYield; + + state.allowYield = false; + params = parseParams(); + state.allowYield = previousAllowYield; + + state.allowYield = false; + method = parsePropertyFunction(node, params, false); + state.allowYield = previousAllowYield; + + return method; + } + + function parseObjectPropertyKey() { + var token, node = new Node(), expr; + + token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + switch (token.type) { + case Token.StringLiteral: + case Token.NumericLiteral: + if (strict && token.octal) { + tolerateUnexpectedToken(token, Messages.StrictOctalLiteral); + } + return node.finishLiteral(token); + case Token.Identifier: + case Token.BooleanLiteral: + case Token.NullLiteral: + case Token.Keyword: + return node.finishIdentifier(token.value); + case Token.Punctuator: + if (token.value === '[') { + expr = isolateCoverGrammar(parseAssignmentExpression); + expect(']'); + return expr; + } + break; + } + throwUnexpectedToken(token); + } + + function lookaheadPropertyName() { + switch (lookahead.type) { + case Token.Identifier: + case Token.StringLiteral: + case Token.BooleanLiteral: + case Token.NullLiteral: + case Token.NumericLiteral: + case Token.Keyword: + return true; + case Token.Punctuator: + return lookahead.value === '['; + } + return false; + } + + // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals, + // it might be called at a position where there is in fact a short hand identifier pattern or a data property. + // This can only be determined after we consumed up to the left parentheses. + // + // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller + // is responsible to visit other options. + function tryParseMethodDefinition(token, key, computed, node) { + var value, options, methodNode, params, + previousAllowYield = state.allowYield; + + if (token.type === Token.Identifier) { + // check for `get` and `set`; + + if (token.value === 'get' && lookaheadPropertyName()) { + computed = match('['); + key = parseObjectPropertyKey(); + methodNode = new Node(); + expect('('); + expect(')'); + + state.allowYield = false; + value = parsePropertyFunction(methodNode, { + params: [], + defaults: [], + stricted: null, + firstRestricted: null, + message: null + }, false); + state.allowYield = previousAllowYield; + + return node.finishProperty('get', key, computed, value, false, false); + } else if (token.value === 'set' && lookaheadPropertyName()) { + computed = match('['); + key = parseObjectPropertyKey(); + methodNode = new Node(); + expect('('); + + options = { + params: [], + defaultCount: 0, + defaults: [], + firstRestricted: null, + paramSet: {} + }; + if (match(')')) { + tolerateUnexpectedToken(lookahead); + } else { + state.allowYield = false; + parseParam(options); + state.allowYield = previousAllowYield; + if (options.defaultCount === 0) { + options.defaults = []; + } + } + expect(')'); + + state.allowYield = false; + value = parsePropertyFunction(methodNode, options, false); + state.allowYield = previousAllowYield; + + return node.finishProperty('set', key, computed, value, false, false); + } + } else if (token.type === Token.Punctuator && token.value === '*' && lookaheadPropertyName()) { + computed = match('['); + key = parseObjectPropertyKey(); + methodNode = new Node(); + + state.allowYield = true; + params = parseParams(); + state.allowYield = previousAllowYield; + + state.allowYield = false; + value = parsePropertyFunction(methodNode, params, true); + state.allowYield = previousAllowYield; + + return node.finishProperty('init', key, computed, value, true, false); + } + + if (key && match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', key, computed, value, true, false); + } + + // Not a MethodDefinition. + return null; + } + + function parseObjectProperty(hasProto) { + var token = lookahead, node = new Node(), computed, key, maybeMethod, proto, value; + + computed = match('['); + if (match('*')) { + lex(); + } else { + key = parseObjectPropertyKey(); + } + maybeMethod = tryParseMethodDefinition(token, key, computed, node); + if (maybeMethod) { + return maybeMethod; + } + + if (!key) { + throwUnexpectedToken(lookahead); + } + + // Check for duplicated __proto__ + if (!computed) { + proto = (key.type === Syntax.Identifier && key.name === '__proto__') || + (key.type === Syntax.Literal && key.value === '__proto__'); + if (hasProto.value && proto) { + tolerateError(Messages.DuplicateProtoProperty); + } + hasProto.value |= proto; + } + + if (match(':')) { + lex(); + value = inheritCoverGrammar(parseAssignmentExpression); + return node.finishProperty('init', key, computed, value, false, false); + } + + if (token.type === Token.Identifier) { + if (match('=')) { + firstCoverInitializedNameError = lookahead; + lex(); + value = isolateCoverGrammar(parseAssignmentExpression); + return node.finishProperty('init', key, computed, + new WrappingNode(token).finishAssignmentPattern(key, value), false, true); + } + return node.finishProperty('init', key, computed, key, false, true); + } + + throwUnexpectedToken(lookahead); + } + + function parseObjectInitializer() { + var properties = [], hasProto = {value: false}, node = new Node(); + + expect('{'); + + while (!match('}')) { + properties.push(parseObjectProperty(hasProto)); + + if (!match('}')) { + expectCommaSeparator(); + } + } + + expect('}'); + + return node.finishObjectExpression(properties); + } + + function reinterpretExpressionAsPattern(expr) { + var i; + switch (expr.type) { + case Syntax.Identifier: + case Syntax.MemberExpression: + case Syntax.RestElement: + case Syntax.AssignmentPattern: + break; + case Syntax.SpreadElement: + expr.type = Syntax.RestElement; + reinterpretExpressionAsPattern(expr.argument); + break; + case Syntax.ArrayExpression: + expr.type = Syntax.ArrayPattern; + for (i = 0; i < expr.elements.length; i++) { + if (expr.elements[i] !== null) { + reinterpretExpressionAsPattern(expr.elements[i]); + } + } + break; + case Syntax.ObjectExpression: + expr.type = Syntax.ObjectPattern; + for (i = 0; i < expr.properties.length; i++) { + reinterpretExpressionAsPattern(expr.properties[i].value); + } + break; + case Syntax.AssignmentExpression: + expr.type = Syntax.AssignmentPattern; + reinterpretExpressionAsPattern(expr.left); + break; + default: + // Allow other node type for tolerant parsing. + break; + } + } + + // ECMA-262 12.2.9 Template Literals + + function parseTemplateElement(option) { + var node, token; + + if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) { + throwUnexpectedToken(); + } + + node = new Node(); + token = lex(); + + return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail); + } + + function parseTemplateLiteral() { + var quasi, quasis, expressions, node = new Node(); + + quasi = parseTemplateElement({ head: true }); + quasis = [quasi]; + expressions = []; + + while (!quasi.tail) { + expressions.push(parseExpression()); + quasi = parseTemplateElement({ head: false }); + quasis.push(quasi); + } + + return node.finishTemplateLiteral(quasis, expressions); + } + + // ECMA-262 12.2.10 The Grouping Operator + + function parseGroupExpression() { + var expr, expressions, startToken, i, params = []; + + expect('('); + + if (match(')')) { + lex(); + if (!match('=>')) { + expect('=>'); + } + return { + type: PlaceHolders.ArrowParameterPlaceHolder, + params: [], + rawParams: [] + }; + } + + startToken = lookahead; + if (match('...')) { + expr = parseRestElement(params); + expect(')'); + if (!match('=>')) { + expect('=>'); + } + return { + type: PlaceHolders.ArrowParameterPlaceHolder, + params: [expr] + }; + } + + isBindingElement = true; + expr = inheritCoverGrammar(parseAssignmentExpression); + + if (match(',')) { + isAssignmentTarget = false; + expressions = [expr]; + + while (startIndex < length) { + if (!match(',')) { + break; + } + lex(); + + if (match('...')) { + if (!isBindingElement) { + throwUnexpectedToken(lookahead); + } + expressions.push(parseRestElement(params)); + expect(')'); + if (!match('=>')) { + expect('=>'); + } + isBindingElement = false; + for (i = 0; i < expressions.length; i++) { + reinterpretExpressionAsPattern(expressions[i]); + } + return { + type: PlaceHolders.ArrowParameterPlaceHolder, + params: expressions + }; + } + + expressions.push(inheritCoverGrammar(parseAssignmentExpression)); + } + + expr = new WrappingNode(startToken).finishSequenceExpression(expressions); + } + + + expect(')'); + + if (match('=>')) { + if (expr.type === Syntax.Identifier && expr.name === 'yield') { + return { + type: PlaceHolders.ArrowParameterPlaceHolder, + params: [expr] + }; + } + + if (!isBindingElement) { + throwUnexpectedToken(lookahead); + } + + if (expr.type === Syntax.SequenceExpression) { + for (i = 0; i < expr.expressions.length; i++) { + reinterpretExpressionAsPattern(expr.expressions[i]); + } + } else { + reinterpretExpressionAsPattern(expr); + } + + expr = { + type: PlaceHolders.ArrowParameterPlaceHolder, + params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr] + }; + } + isBindingElement = false; + return expr; + } + + + // ECMA-262 12.2 Primary Expressions + + function parsePrimaryExpression() { + var type, token, expr, node; + + if (match('(')) { + isBindingElement = false; + return inheritCoverGrammar(parseGroupExpression); + } + + if (match('[')) { + return inheritCoverGrammar(parseArrayInitializer); + } + + if (match('{')) { + return inheritCoverGrammar(parseObjectInitializer); + } + + type = lookahead.type; + node = new Node(); + + if (type === Token.Identifier) { + if (state.sourceType === 'module' && lookahead.value === 'await') { + tolerateUnexpectedToken(lookahead); + } + expr = node.finishIdentifier(lex().value); + } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { + isAssignmentTarget = isBindingElement = false; + if (strict && lookahead.octal) { + tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral); + } + expr = node.finishLiteral(lex()); + } else if (type === Token.Keyword) { + if (!strict && state.allowYield && matchKeyword('yield')) { + return parseNonComputedProperty(); + } + if (!strict && matchKeyword('let')) { + return node.finishIdentifier(lex().value); + } + isAssignmentTarget = isBindingElement = false; + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + if (matchKeyword('this')) { + lex(); + return node.finishThisExpression(); + } + if (matchKeyword('class')) { + return parseClassExpression(); + } + throwUnexpectedToken(lex()); + } else if (type === Token.BooleanLiteral) { + isAssignmentTarget = isBindingElement = false; + token = lex(); + token.value = (token.value === 'true'); + expr = node.finishLiteral(token); + } else if (type === Token.NullLiteral) { + isAssignmentTarget = isBindingElement = false; + token = lex(); + token.value = null; + expr = node.finishLiteral(token); + } else if (match('/') || match('/=')) { + isAssignmentTarget = isBindingElement = false; + index = startIndex; + + if (typeof extra.tokens !== 'undefined') { + token = collectRegex(); + } else { + token = scanRegExp(); + } + lex(); + expr = node.finishLiteral(token); + } else if (type === Token.Template) { + expr = parseTemplateLiteral(); + } else { + throwUnexpectedToken(lex()); + } + + return expr; + } + + // ECMA-262 12.3 Left-Hand-Side Expressions + + function parseArguments() { + var args = [], expr; + + expect('('); + + if (!match(')')) { + while (startIndex < length) { + if (match('...')) { + expr = new Node(); + lex(); + expr.finishSpreadElement(isolateCoverGrammar(parseAssignmentExpression)); + } else { + expr = isolateCoverGrammar(parseAssignmentExpression); + } + args.push(expr); + if (match(')')) { + break; + } + expectCommaSeparator(); + } + } + + expect(')'); + + return args; + } + + function parseNonComputedProperty() { + var token, node = new Node(); + + token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpectedToken(token); + } + + return node.finishIdentifier(token.value); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = isolateCoverGrammar(parseExpression); + + expect(']'); + + return expr; + } + + // ECMA-262 12.3.3 The new Operator + + function parseNewExpression() { + var callee, args, node = new Node(); + + expectKeyword('new'); + + if (match('.')) { + lex(); + if (lookahead.type === Token.Identifier && lookahead.value === 'target') { + if (state.inFunctionBody) { + lex(); + return node.finishMetaProperty('new', 'target'); + } + } + throwUnexpectedToken(lookahead); + } + + callee = isolateCoverGrammar(parseLeftHandSideExpression); + args = match('(') ? parseArguments() : []; + + isAssignmentTarget = isBindingElement = false; + + return node.finishNewExpression(callee, args); + } + + // ECMA-262 12.3.4 Function Calls + + function parseLeftHandSideExpressionAllowCall() { + var quasi, expr, args, property, startToken, previousAllowIn = state.allowIn; + + startToken = lookahead; + state.allowIn = true; + + if (matchKeyword('super') && state.inFunctionBody) { + expr = new Node(); + lex(); + expr = expr.finishSuper(); + if (!match('(') && !match('.') && !match('[')) { + throwUnexpectedToken(lookahead); + } + } else { + expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression); + } + + for (;;) { + if (match('.')) { + isBindingElement = false; + isAssignmentTarget = true; + property = parseNonComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); + } else if (match('(')) { + isBindingElement = false; + isAssignmentTarget = false; + args = parseArguments(); + expr = new WrappingNode(startToken).finishCallExpression(expr, args); + } else if (match('[')) { + isBindingElement = false; + isAssignmentTarget = true; + property = parseComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); + } else if (lookahead.type === Token.Template && lookahead.head) { + quasi = parseTemplateLiteral(); + expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi); + } else { + break; + } + } + state.allowIn = previousAllowIn; + + return expr; + } + + // ECMA-262 12.3 Left-Hand-Side Expressions + + function parseLeftHandSideExpression() { + var quasi, expr, property, startToken; + assert(state.allowIn, 'callee of new expression always allow in keyword.'); + + startToken = lookahead; + + if (matchKeyword('super') && state.inFunctionBody) { + expr = new Node(); + lex(); + expr = expr.finishSuper(); + if (!match('[') && !match('.')) { + throwUnexpectedToken(lookahead); + } + } else { + expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression); + } + + for (;;) { + if (match('[')) { + isBindingElement = false; + isAssignmentTarget = true; + property = parseComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); + } else if (match('.')) { + isBindingElement = false; + isAssignmentTarget = true; + property = parseNonComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); + } else if (lookahead.type === Token.Template && lookahead.head) { + quasi = parseTemplateLiteral(); + expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi); + } else { + break; + } + } + return expr; + } + + // ECMA-262 12.4 Postfix Expressions + + function parsePostfixExpression() { + var expr, token, startToken = lookahead; + + expr = inheritCoverGrammar(parseLeftHandSideExpressionAllowCall); + + if (!hasLineTerminator && lookahead.type === Token.Punctuator) { + if (match('++') || match('--')) { + // ECMA-262 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateError(Messages.StrictLHSPostfix); + } + + if (!isAssignmentTarget) { + tolerateError(Messages.InvalidLHSInAssignment); + } + + isAssignmentTarget = isBindingElement = false; + + token = lex(); + expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr); + } + } + + return expr; + } + + // ECMA-262 12.5 Unary Operators + + function parseUnaryExpression() { + var token, expr, startToken; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + expr = parsePostfixExpression(); + } else if (match('++') || match('--')) { + startToken = lookahead; + token = lex(); + expr = inheritCoverGrammar(parseUnaryExpression); + // ECMA-262 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateError(Messages.StrictLHSPrefix); + } + + if (!isAssignmentTarget) { + tolerateError(Messages.InvalidLHSInAssignment); + } + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); + isAssignmentTarget = isBindingElement = false; + } else if (match('+') || match('-') || match('~') || match('!')) { + startToken = lookahead; + token = lex(); + expr = inheritCoverGrammar(parseUnaryExpression); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); + isAssignmentTarget = isBindingElement = false; + } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + startToken = lookahead; + token = lex(); + expr = inheritCoverGrammar(parseUnaryExpression); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + tolerateError(Messages.StrictDelete); + } + isAssignmentTarget = isBindingElement = false; + } else { + expr = parsePostfixExpression(); + } + + return expr; + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // ECMA-262 12.6 Multiplicative Operators + // ECMA-262 12.7 Additive Operators + // ECMA-262 12.8 Bitwise Shift Operators + // ECMA-262 12.9 Relational Operators + // ECMA-262 12.10 Equality Operators + // ECMA-262 12.11 Binary Bitwise Operators + // ECMA-262 12.12 Binary Logical Operators + + function parseBinaryExpression() { + var marker, markers, expr, token, prec, stack, right, operator, left, i; + + marker = lookahead; + left = inheritCoverGrammar(parseUnaryExpression); + + token = lookahead; + prec = binaryPrecedence(token, state.allowIn); + if (prec === 0) { + return left; + } + isAssignmentTarget = isBindingElement = false; + token.prec = prec; + lex(); + + markers = [marker, lookahead]; + right = isolateCoverGrammar(parseUnaryExpression); + + stack = [left, token, right]; + + while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { + + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + markers.pop(); + expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right); + stack.push(expr); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + markers.push(lookahead); + expr = isolateCoverGrammar(parseUnaryExpression); + stack.push(expr); + } + + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + markers.pop(); + while (i > 1) { + expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + } + + return expr; + } + + + // ECMA-262 12.13 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate, startToken; + + startToken = lookahead; + + expr = inheritCoverGrammar(parseBinaryExpression); + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = isolateCoverGrammar(parseAssignmentExpression); + state.allowIn = previousAllowIn; + expect(':'); + alternate = isolateCoverGrammar(parseAssignmentExpression); + + expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate); + isAssignmentTarget = isBindingElement = false; + } + + return expr; + } + + // ECMA-262 14.2 Arrow Function Definitions + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return isolateCoverGrammar(parseAssignmentExpression); + } + + function checkPatternParam(options, param) { + var i; + switch (param.type) { + case Syntax.Identifier: + validateParam(options, param, param.name); + break; + case Syntax.RestElement: + checkPatternParam(options, param.argument); + break; + case Syntax.AssignmentPattern: + checkPatternParam(options, param.left); + break; + case Syntax.ArrayPattern: + for (i = 0; i < param.elements.length; i++) { + if (param.elements[i] !== null) { + checkPatternParam(options, param.elements[i]); + } + } + break; + case Syntax.YieldExpression: + break; + default: + assert(param.type === Syntax.ObjectPattern, 'Invalid type'); + for (i = 0; i < param.properties.length; i++) { + checkPatternParam(options, param.properties[i].value); + } + break; + } + } + function reinterpretAsCoverFormalsList(expr) { + var i, len, param, params, defaults, defaultCount, options, token; + + defaults = []; + defaultCount = 0; + params = [expr]; + + switch (expr.type) { + case Syntax.Identifier: + break; + case PlaceHolders.ArrowParameterPlaceHolder: + params = expr.params; + break; + default: + return null; + } + + options = { + paramSet: {} + }; + + for (i = 0, len = params.length; i < len; i += 1) { + param = params[i]; + switch (param.type) { + case Syntax.AssignmentPattern: + params[i] = param.left; + if (param.right.type === Syntax.YieldExpression) { + if (param.right.argument) { + throwUnexpectedToken(lookahead); + } + param.right.type = Syntax.Identifier; + param.right.name = 'yield'; + delete param.right.argument; + delete param.right.delegate; + } + defaults.push(param.right); + ++defaultCount; + checkPatternParam(options, param.left); + break; + default: + checkPatternParam(options, param); + params[i] = param; + defaults.push(null); + break; + } + } + + if (strict || !state.allowYield) { + for (i = 0, len = params.length; i < len; i += 1) { + param = params[i]; + if (param.type === Syntax.YieldExpression) { + throwUnexpectedToken(lookahead); + } + } + } + + if (options.message === Messages.StrictParamDupe) { + token = strict ? options.stricted : options.firstRestricted; + throwUnexpectedToken(token, options.message); + } + + if (defaultCount === 0) { + defaults = []; + } + + return { + params: params, + defaults: defaults, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseArrowFunctionExpression(options, node) { + var previousStrict, previousAllowYield, body; + + if (hasLineTerminator) { + tolerateUnexpectedToken(lookahead); + } + expect('=>'); + + previousStrict = strict; + previousAllowYield = state.allowYield; + state.allowYield = true; + + body = parseConciseBody(); + + if (strict && options.firstRestricted) { + throwUnexpectedToken(options.firstRestricted, options.message); + } + if (strict && options.stricted) { + tolerateUnexpectedToken(options.stricted, options.message); + } + + strict = previousStrict; + state.allowYield = previousAllowYield; + + return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement); + } + + // ECMA-262 14.4 Yield expression + + function parseYieldExpression() { + var argument, expr, delegate, previousAllowYield; + + argument = null; + expr = new Node(); + delegate = false; + + expectKeyword('yield'); + + if (!hasLineTerminator) { + previousAllowYield = state.allowYield; + state.allowYield = false; + delegate = match('*'); + if (delegate) { + lex(); + argument = parseAssignmentExpression(); + } else { + if (!match(';') && !match('}') && !match(')') && lookahead.type !== Token.EOF) { + argument = parseAssignmentExpression(); + } + } + state.allowYield = previousAllowYield; + } + + return expr.finishYieldExpression(argument, delegate); + } + + // ECMA-262 12.14 Assignment Operators + + function parseAssignmentExpression() { + var token, expr, right, list, startToken; + + startToken = lookahead; + token = lookahead; + + if (!state.allowYield && matchKeyword('yield')) { + return parseYieldExpression(); + } + + expr = parseConditionalExpression(); + + if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) { + isAssignmentTarget = isBindingElement = false; + list = reinterpretAsCoverFormalsList(expr); + + if (list) { + firstCoverInitializedNameError = null; + return parseArrowFunctionExpression(list, new WrappingNode(startToken)); + } + + return expr; + } + + if (matchAssign()) { + if (!isAssignmentTarget) { + tolerateError(Messages.InvalidLHSInAssignment); + } + + // ECMA-262 12.1.1 + if (strict && expr.type === Syntax.Identifier) { + if (isRestrictedWord(expr.name)) { + tolerateUnexpectedToken(token, Messages.StrictLHSAssignment); + } + if (isStrictModeReservedWord(expr.name)) { + tolerateUnexpectedToken(token, Messages.StrictReservedWord); + } + } + + if (!match('=')) { + isAssignmentTarget = isBindingElement = false; + } else { + reinterpretExpressionAsPattern(expr); + } + + token = lex(); + right = isolateCoverGrammar(parseAssignmentExpression); + expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right); + firstCoverInitializedNameError = null; + } + + return expr; + } + + // ECMA-262 12.15 Comma Operator + + function parseExpression() { + var expr, startToken = lookahead, expressions; + + expr = isolateCoverGrammar(parseAssignmentExpression); + + if (match(',')) { + expressions = [expr]; + + while (startIndex < length) { + if (!match(',')) { + break; + } + lex(); + expressions.push(isolateCoverGrammar(parseAssignmentExpression)); + } + + expr = new WrappingNode(startToken).finishSequenceExpression(expressions); + } + + return expr; + } + + // ECMA-262 13.2 Block + + function parseStatementListItem() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'export': + if (state.sourceType !== 'module') { + tolerateUnexpectedToken(lookahead, Messages.IllegalExportDeclaration); + } + return parseExportDeclaration(); + case 'import': + if (state.sourceType !== 'module') { + tolerateUnexpectedToken(lookahead, Messages.IllegalImportDeclaration); + } + return parseImportDeclaration(); + case 'const': + return parseLexicalDeclaration({inFor: false}); + case 'function': + return parseFunctionDeclaration(new Node()); + case 'class': + return parseClassDeclaration(); + } + } + + if (matchKeyword('let') && isLexicalDeclaration()) { + return parseLexicalDeclaration({inFor: false}); + } + + return parseStatement(); + } + + function parseStatementList() { + var list = []; + while (startIndex < length) { + if (match('}')) { + break; + } + list.push(parseStatementListItem()); + } + + return list; + } + + function parseBlock() { + var block, node = new Node(); + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return node.finishBlockStatement(block); + } + + // ECMA-262 13.3.2 Variable Statement + + function parseVariableIdentifier(kind) { + var token, node = new Node(); + + token = lex(); + + if (token.type === Token.Keyword && token.value === 'yield') { + if (strict) { + tolerateUnexpectedToken(token, Messages.StrictReservedWord); + } if (!state.allowYield) { + throwUnexpectedToken(token); + } + } else if (token.type !== Token.Identifier) { + if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictReservedWord); + } else { + if (strict || token.value !== 'let' || kind !== 'var') { + throwUnexpectedToken(token); + } + } + } else if (state.sourceType === 'module' && token.type === Token.Identifier && token.value === 'await') { + tolerateUnexpectedToken(token); + } + + return node.finishIdentifier(token.value); + } + + function parseVariableDeclaration(options) { + var init = null, id, node = new Node(), params = []; + + id = parsePattern(params, 'var'); + + // ECMA-262 12.2.1 + if (strict && isRestrictedWord(id.name)) { + tolerateError(Messages.StrictVarName); + } + + if (match('=')) { + lex(); + init = isolateCoverGrammar(parseAssignmentExpression); + } else if (id.type !== Syntax.Identifier && !options.inFor) { + expect('='); + } + + return node.finishVariableDeclarator(id, init); + } + + function parseVariableDeclarationList(options) { + var opt, list; + + opt = { inFor: options.inFor }; + list = [parseVariableDeclaration(opt)]; + + while (match(',')) { + lex(); + list.push(parseVariableDeclaration(opt)); + } + + return list; + } + + function parseVariableStatement(node) { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList({ inFor: false }); + + consumeSemicolon(); + + return node.finishVariableDeclaration(declarations); + } + + // ECMA-262 13.3.1 Let and Const Declarations + + function parseLexicalBinding(kind, options) { + var init = null, id, node = new Node(), params = []; + + id = parsePattern(params, kind); + + // ECMA-262 12.2.1 + if (strict && id.type === Syntax.Identifier && isRestrictedWord(id.name)) { + tolerateError(Messages.StrictVarName); + } + + if (kind === 'const') { + if (!matchKeyword('in') && !matchContextualKeyword('of')) { + expect('='); + init = isolateCoverGrammar(parseAssignmentExpression); + } + } else if ((!options.inFor && id.type !== Syntax.Identifier) || match('=')) { + expect('='); + init = isolateCoverGrammar(parseAssignmentExpression); + } + + return node.finishVariableDeclarator(id, init); + } + + function parseBindingList(kind, options) { + var list = [parseLexicalBinding(kind, options)]; + + while (match(',')) { + lex(); + list.push(parseLexicalBinding(kind, options)); + } + + return list; + } + + + function tokenizerState() { + return { + index: index, + lineNumber: lineNumber, + lineStart: lineStart, + hasLineTerminator: hasLineTerminator, + lastIndex: lastIndex, + lastLineNumber: lastLineNumber, + lastLineStart: lastLineStart, + startIndex: startIndex, + startLineNumber: startLineNumber, + startLineStart: startLineStart, + lookahead: lookahead, + tokenCount: extra.tokens ? extra.tokens.length : 0 + }; + } + + function resetTokenizerState(ts) { + index = ts.index; + lineNumber = ts.lineNumber; + lineStart = ts.lineStart; + hasLineTerminator = ts.hasLineTerminator; + lastIndex = ts.lastIndex; + lastLineNumber = ts.lastLineNumber; + lastLineStart = ts.lastLineStart; + startIndex = ts.startIndex; + startLineNumber = ts.startLineNumber; + startLineStart = ts.startLineStart; + lookahead = ts.lookahead; + if (extra.tokens) { + extra.tokens.splice(ts.tokenCount, extra.tokens.length); + } + } + + function isLexicalDeclaration() { + var lexical, ts; + + ts = tokenizerState(); + + lex(); + lexical = (lookahead.type === Token.Identifier) || match('[') || match('{') || + matchKeyword('let') || matchKeyword('yield'); + + resetTokenizerState(ts); + + return lexical; + } + + function parseLexicalDeclaration(options) { + var kind, declarations, node = new Node(); + + kind = lex().value; + assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const'); + + declarations = parseBindingList(kind, options); + + consumeSemicolon(); + + return node.finishLexicalDeclaration(declarations, kind); + } + + function parseRestElement(params) { + var param, node = new Node(); + + lex(); + + if (match('{')) { + throwError(Messages.ObjectPatternAsRestParameter); + } + + params.push(lookahead); + + param = parseVariableIdentifier(); + + if (match('=')) { + throwError(Messages.DefaultRestParameter); + } + + if (!match(')')) { + throwError(Messages.ParameterAfterRestParameter); + } + + return node.finishRestElement(param); + } + + // ECMA-262 13.4 Empty Statement + + function parseEmptyStatement(node) { + expect(';'); + return node.finishEmptyStatement(); + } + + // ECMA-262 12.4 Expression Statement + + function parseExpressionStatement(node) { + var expr = parseExpression(); + consumeSemicolon(); + return node.finishExpressionStatement(expr); + } + + // ECMA-262 13.6 If statement + + function parseIfStatement(node) { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return node.finishIfStatement(test, consequent, alternate); + } + + // ECMA-262 13.7 Iteration Statements + + function parseDoWhileStatement(node) { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return node.finishDoWhileStatement(body, test); + } + + function parseWhileStatement(node) { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return node.finishWhileStatement(test, body); + } + + function parseForStatement(node) { + var init, forIn, initSeq, initStartToken, test, update, left, right, kind, declarations, + body, oldInIteration, previousAllowIn = state.allowIn; + + init = test = update = null; + forIn = true; + + expectKeyword('for'); + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var')) { + init = new Node(); + lex(); + + state.allowIn = false; + declarations = parseVariableDeclarationList({ inFor: true }); + state.allowIn = previousAllowIn; + + if (declarations.length === 1 && matchKeyword('in')) { + init = init.finishVariableDeclaration(declarations); + lex(); + left = init; + right = parseExpression(); + init = null; + } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) { + init = init.finishVariableDeclaration(declarations); + lex(); + left = init; + right = parseAssignmentExpression(); + init = null; + forIn = false; + } else { + init = init.finishVariableDeclaration(declarations); + expect(';'); + } + } else if (matchKeyword('const') || matchKeyword('let')) { + init = new Node(); + kind = lex().value; + + if (!strict && lookahead.value === 'in') { + init = init.finishIdentifier(kind); + lex(); + left = init; + right = parseExpression(); + init = null; + } else { + state.allowIn = false; + declarations = parseBindingList(kind, {inFor: true}); + state.allowIn = previousAllowIn; + + if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) { + init = init.finishLexicalDeclaration(declarations, kind); + lex(); + left = init; + right = parseExpression(); + init = null; + } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) { + init = init.finishLexicalDeclaration(declarations, kind); + lex(); + left = init; + right = parseAssignmentExpression(); + init = null; + forIn = false; + } else { + consumeSemicolon(); + init = init.finishLexicalDeclaration(declarations, kind); + } + } + } else { + initStartToken = lookahead; + state.allowIn = false; + init = inheritCoverGrammar(parseAssignmentExpression); + state.allowIn = previousAllowIn; + + if (matchKeyword('in')) { + if (!isAssignmentTarget) { + tolerateError(Messages.InvalidLHSInForIn); + } + + lex(); + reinterpretExpressionAsPattern(init); + left = init; + right = parseExpression(); + init = null; + } else if (matchContextualKeyword('of')) { + if (!isAssignmentTarget) { + tolerateError(Messages.InvalidLHSInForLoop); + } + + lex(); + reinterpretExpressionAsPattern(init); + left = init; + right = parseAssignmentExpression(); + init = null; + forIn = false; + } else { + if (match(',')) { + initSeq = [init]; + while (match(',')) { + lex(); + initSeq.push(isolateCoverGrammar(parseAssignmentExpression)); + } + init = new WrappingNode(initStartToken).finishSequenceExpression(initSeq); + } + expect(';'); + } + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = isolateCoverGrammar(parseStatement); + + state.inIteration = oldInIteration; + + return (typeof left === 'undefined') ? + node.finishForStatement(init, test, update, body) : + forIn ? node.finishForInStatement(left, right, body) : + node.finishForOfStatement(left, right, body); + } + + // ECMA-262 13.8 The continue statement + + function parseContinueStatement(node) { + var label = null, key; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source.charCodeAt(startIndex) === 0x3B) { + lex(); + + if (!state.inIteration) { + throwError(Messages.IllegalContinue); + } + + return node.finishContinueStatement(null); + } + + if (hasLineTerminator) { + if (!state.inIteration) { + throwError(Messages.IllegalContinue); + } + + return node.finishContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError(Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError(Messages.IllegalContinue); + } + + return node.finishContinueStatement(label); + } + + // ECMA-262 13.9 The break statement + + function parseBreakStatement(node) { + var label = null, key; + + expectKeyword('break'); + + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(lastIndex) === 0x3B) { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError(Messages.IllegalBreak); + } + + return node.finishBreakStatement(null); + } + + if (hasLineTerminator) { + if (!(state.inIteration || state.inSwitch)) { + throwError(Messages.IllegalBreak); + } + } else if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError(Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError(Messages.IllegalBreak); + } + + return node.finishBreakStatement(label); + } + + // ECMA-262 13.10 The return statement + + function parseReturnStatement(node) { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + tolerateError(Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source.charCodeAt(lastIndex) === 0x20) { + if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) { + argument = parseExpression(); + consumeSemicolon(); + return node.finishReturnStatement(argument); + } + } + + if (hasLineTerminator) { + // HACK + return node.finishReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return node.finishReturnStatement(argument); + } + + // ECMA-262 13.11 The with statement + + function parseWithStatement(node) { + var object, body; + + if (strict) { + tolerateError(Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return node.finishWithStatement(object, body); + } + + // ECMA-262 13.12 The switch statement + + function parseSwitchCase() { + var test, consequent = [], statement, node = new Node(); + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (startIndex < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + statement = parseStatementListItem(); + consequent.push(statement); + } + + return node.finishSwitchCase(test, consequent); + } + + function parseSwitchStatement(node) { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + cases = []; + + if (match('}')) { + lex(); + return node.finishSwitchStatement(discriminant, cases); + } + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (startIndex < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError(Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return node.finishSwitchStatement(discriminant, cases); + } + + // ECMA-262 13.14 The throw statement + + function parseThrowStatement(node) { + var argument; + + expectKeyword('throw'); + + if (hasLineTerminator) { + throwError(Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return node.finishThrowStatement(argument); + } + + // ECMA-262 13.15 The try statement + + function parseCatchClause() { + var param, params = [], paramMap = {}, key, i, body, node = new Node(); + + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpectedToken(lookahead); + } + + param = parsePattern(params); + for (i = 0; i < params.length; i++) { + key = '$' + params[i].value; + if (Object.prototype.hasOwnProperty.call(paramMap, key)) { + tolerateError(Messages.DuplicateBinding, params[i].value); + } + paramMap[key] = true; + } + + // ECMA-262 12.14.1 + if (strict && isRestrictedWord(param.name)) { + tolerateError(Messages.StrictCatchVariable); + } + + expect(')'); + body = parseBlock(); + return node.finishCatchClause(param, body); + } + + function parseTryStatement(node) { + var block, handler = null, finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handler = parseCatchClause(); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (!handler && !finalizer) { + throwError(Messages.NoCatchOrFinally); + } + + return node.finishTryStatement(block, handler, finalizer); + } + + // ECMA-262 13.16 The debugger statement + + function parseDebuggerStatement(node) { + expectKeyword('debugger'); + + consumeSemicolon(); + + return node.finishDebuggerStatement(); + } + + // 13 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody, + key, + node; + + if (type === Token.EOF) { + throwUnexpectedToken(lookahead); + } + + if (type === Token.Punctuator && lookahead.value === '{') { + return parseBlock(); + } + isAssignmentTarget = isBindingElement = true; + node = new Node(); + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return parseEmptyStatement(node); + case '(': + return parseExpressionStatement(node); + default: + break; + } + } else if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return parseBreakStatement(node); + case 'continue': + return parseContinueStatement(node); + case 'debugger': + return parseDebuggerStatement(node); + case 'do': + return parseDoWhileStatement(node); + case 'for': + return parseForStatement(node); + case 'function': + return parseFunctionDeclaration(node); + case 'if': + return parseIfStatement(node); + case 'return': + return parseReturnStatement(node); + case 'switch': + return parseSwitchStatement(node); + case 'throw': + return parseThrowStatement(node); + case 'try': + return parseTryStatement(node); + case 'var': + return parseVariableStatement(node); + case 'while': + return parseWhileStatement(node); + case 'with': + return parseWithStatement(node); + default: + break; + } + } + + expr = parseExpression(); + + // ECMA-262 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError(Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[key] = true; + labeledBody = parseStatement(); + delete state.labelSet[key]; + return node.finishLabeledStatement(expr, labeledBody); + } + + consumeSemicolon(); + + return node.finishExpressionStatement(expr); + } + + // ECMA-262 14.1 Function Definition + + function parseFunctionSourceElements() { + var statement, body = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, + node = new Node(); + + expect('{'); + + while (startIndex < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + statement = parseStatementListItem(); + body.push(statement); + if (statement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + + while (startIndex < length) { + if (match('}')) { + break; + } + body.push(parseStatementListItem()); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + + return node.finishBlockStatement(body); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, param, params = [], i, def; + + token = lookahead; + if (token.value === '...') { + param = parseRestElement(params); + validateParam(options, param.argument, param.argument.name); + options.params.push(param); + options.defaults.push(null); + return false; + } + + param = parsePatternWithDefault(params); + for (i = 0; i < params.length; i++) { + validateParam(options, params[i], params[i].value); + } + + if (param.type === Syntax.AssignmentPattern) { + def = param.right; + param = param.left; + ++options.defaultCount; + } + + options.params.push(param); + options.defaults.push(def); + + return !match(')'); + } + + function parseParams(firstRestricted) { + var options; + + options = { + params: [], + defaultCount: 0, + defaults: [], + firstRestricted: firstRestricted + }; + + expect('('); + + if (!match(')')) { + options.paramSet = {}; + while (startIndex < length) { + if (!parseParam(options)) { + break; + } + expect(','); + } + } + + expect(')'); + + if (options.defaultCount === 0) { + options.defaults = []; + } + + return { + params: options.params, + defaults: options.defaults, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseFunctionDeclaration(node, identifierIsOptional) { + var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, + isGenerator, previousAllowYield; + + previousAllowYield = state.allowYield; + + expectKeyword('function'); + + isGenerator = match('*'); + if (isGenerator) { + lex(); + } + + if (!identifierIsOptional || !match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + state.allowYield = !isGenerator; + tmp = parseParams(firstRestricted); + params = tmp.params; + defaults = tmp.defaults; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwUnexpectedToken(firstRestricted, message); + } + if (strict && stricted) { + tolerateUnexpectedToken(stricted, message); + } + + strict = previousStrict; + state.allowYield = previousAllowYield; + + return node.finishFunctionDeclaration(id, params, defaults, body, isGenerator); + } + + function parseFunctionExpression() { + var token, id = null, stricted, firstRestricted, message, tmp, + params = [], defaults = [], body, previousStrict, node = new Node(), + isGenerator, previousAllowYield; + + previousAllowYield = state.allowYield; + + expectKeyword('function'); + + isGenerator = match('*'); + if (isGenerator) { + lex(); + } + + state.allowYield = !isGenerator; + if (!match('(')) { + token = lookahead; + id = (!strict && !isGenerator && matchKeyword('yield')) ? parseNonComputedProperty() : parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + defaults = tmp.defaults; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwUnexpectedToken(firstRestricted, message); + } + if (strict && stricted) { + tolerateUnexpectedToken(stricted, message); + } + strict = previousStrict; + state.allowYield = previousAllowYield; + + return node.finishFunctionExpression(id, params, defaults, body, isGenerator); + } + + // ECMA-262 14.5 Class Definitions + + function parseClassBody() { + var classBody, token, isStatic, hasConstructor = false, body, method, computed, key; + + classBody = new Node(); + + expect('{'); + body = []; + while (!match('}')) { + if (match(';')) { + lex(); + } else { + method = new Node(); + token = lookahead; + isStatic = false; + computed = match('['); + if (match('*')) { + lex(); + } else { + key = parseObjectPropertyKey(); + if (key.name === 'static' && (lookaheadPropertyName() || match('*'))) { + token = lookahead; + isStatic = true; + computed = match('['); + if (match('*')) { + lex(); + } else { + key = parseObjectPropertyKey(); + } + } + } + method = tryParseMethodDefinition(token, key, computed, method); + if (method) { + method['static'] = isStatic; // jscs:ignore requireDotNotation + if (method.kind === 'init') { + method.kind = 'method'; + } + if (!isStatic) { + if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') { + if (method.kind !== 'method' || !method.method || method.value.generator) { + throwUnexpectedToken(token, Messages.ConstructorSpecialMethod); + } + if (hasConstructor) { + throwUnexpectedToken(token, Messages.DuplicateConstructor); + } else { + hasConstructor = true; + } + method.kind = 'constructor'; + } + } else { + if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') { + throwUnexpectedToken(token, Messages.StaticPrototype); + } + } + method.type = Syntax.MethodDefinition; + delete method.method; + delete method.shorthand; + body.push(method); + } else { + throwUnexpectedToken(lookahead); + } + } + } + lex(); + return classBody.finishClassBody(body); + } + + function parseClassDeclaration(identifierIsOptional) { + var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict; + strict = true; + + expectKeyword('class'); + + if (!identifierIsOptional || lookahead.type === Token.Identifier) { + id = parseVariableIdentifier(); + } + + if (matchKeyword('extends')) { + lex(); + superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall); + } + classBody = parseClassBody(); + strict = previousStrict; + + return classNode.finishClassDeclaration(id, superClass, classBody); + } + + function parseClassExpression() { + var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict; + strict = true; + + expectKeyword('class'); + + if (lookahead.type === Token.Identifier) { + id = parseVariableIdentifier(); + } + + if (matchKeyword('extends')) { + lex(); + superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall); + } + classBody = parseClassBody(); + strict = previousStrict; + + return classNode.finishClassExpression(id, superClass, classBody); + } + + // ECMA-262 15.2 Modules + + function parseModuleSpecifier() { + var node = new Node(); + + if (lookahead.type !== Token.StringLiteral) { + throwError(Messages.InvalidModuleSpecifier); + } + return node.finishLiteral(lex()); + } + + // ECMA-262 15.2.3 Exports + + function parseExportSpecifier() { + var exported, local, node = new Node(), def; + if (matchKeyword('default')) { + // export {default} from 'something'; + def = new Node(); + lex(); + local = def.finishIdentifier('default'); + } else { + local = parseVariableIdentifier(); + } + if (matchContextualKeyword('as')) { + lex(); + exported = parseNonComputedProperty(); + } + return node.finishExportSpecifier(local, exported); + } + + function parseExportNamedDeclaration(node) { + var declaration = null, + isExportFromIdentifier, + src = null, specifiers = []; + + // non-default export + if (lookahead.type === Token.Keyword) { + // covers: + // export var f = 1; + switch (lookahead.value) { + case 'let': + case 'const': + declaration = parseLexicalDeclaration({inFor: false}); + return node.finishExportNamedDeclaration(declaration, specifiers, null); + case 'var': + case 'class': + case 'function': + declaration = parseStatementListItem(); + return node.finishExportNamedDeclaration(declaration, specifiers, null); + } + } + + expect('{'); + while (!match('}')) { + isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default'); + specifiers.push(parseExportSpecifier()); + if (!match('}')) { + expect(','); + if (match('}')) { + break; + } + } + } + expect('}'); + + if (matchContextualKeyword('from')) { + // covering: + // export {default} from 'foo'; + // export {foo} from 'foo'; + lex(); + src = parseModuleSpecifier(); + consumeSemicolon(); + } else if (isExportFromIdentifier) { + // covering: + // export {default}; // missing fromClause + throwError(lookahead.value ? + Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); + } else { + // cover + // export {foo}; + consumeSemicolon(); + } + return node.finishExportNamedDeclaration(declaration, specifiers, src); + } + + function parseExportDefaultDeclaration(node) { + var declaration = null, + expression = null; + + // covers: + // export default ... + expectKeyword('default'); + + if (matchKeyword('function')) { + // covers: + // export default function foo () {} + // export default function () {} + declaration = parseFunctionDeclaration(new Node(), true); + return node.finishExportDefaultDeclaration(declaration); + } + if (matchKeyword('class')) { + declaration = parseClassDeclaration(true); + return node.finishExportDefaultDeclaration(declaration); + } + + if (matchContextualKeyword('from')) { + throwError(Messages.UnexpectedToken, lookahead.value); + } + + // covers: + // export default {}; + // export default []; + // export default (1 + 2); + if (match('{')) { + expression = parseObjectInitializer(); + } else if (match('[')) { + expression = parseArrayInitializer(); + } else { + expression = parseAssignmentExpression(); + } + consumeSemicolon(); + return node.finishExportDefaultDeclaration(expression); + } + + function parseExportAllDeclaration(node) { + var src; + + // covers: + // export * from 'foo'; + expect('*'); + if (!matchContextualKeyword('from')) { + throwError(lookahead.value ? + Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); + } + lex(); + src = parseModuleSpecifier(); + consumeSemicolon(); + + return node.finishExportAllDeclaration(src); + } + + function parseExportDeclaration() { + var node = new Node(); + if (state.inFunctionBody) { + throwError(Messages.IllegalExportDeclaration); + } + + expectKeyword('export'); + + if (matchKeyword('default')) { + return parseExportDefaultDeclaration(node); + } + if (match('*')) { + return parseExportAllDeclaration(node); + } + return parseExportNamedDeclaration(node); + } + + // ECMA-262 15.2.2 Imports + + function parseImportSpecifier() { + // import {<foo as bar>} ...; + var local, imported, node = new Node(); + + imported = parseNonComputedProperty(); + if (matchContextualKeyword('as')) { + lex(); + local = parseVariableIdentifier(); + } + + return node.finishImportSpecifier(local, imported); + } + + function parseNamedImports() { + var specifiers = []; + // {foo, bar as bas} + expect('{'); + while (!match('}')) { + specifiers.push(parseImportSpecifier()); + if (!match('}')) { + expect(','); + if (match('}')) { + break; + } + } + } + expect('}'); + return specifiers; + } + + function parseImportDefaultSpecifier() { + // import <foo> ...; + var local, node = new Node(); + + local = parseNonComputedProperty(); + + return node.finishImportDefaultSpecifier(local); + } + + function parseImportNamespaceSpecifier() { + // import <* as foo> ...; + var local, node = new Node(); + + expect('*'); + if (!matchContextualKeyword('as')) { + throwError(Messages.NoAsAfterImportNamespace); + } + lex(); + local = parseNonComputedProperty(); + + return node.finishImportNamespaceSpecifier(local); + } + + function parseImportDeclaration() { + var specifiers = [], src, node = new Node(); + + if (state.inFunctionBody) { + throwError(Messages.IllegalImportDeclaration); + } + + expectKeyword('import'); + + if (lookahead.type === Token.StringLiteral) { + // import 'foo'; + src = parseModuleSpecifier(); + } else { + + if (match('{')) { + // import {bar} + specifiers = specifiers.concat(parseNamedImports()); + } else if (match('*')) { + // import * as foo + specifiers.push(parseImportNamespaceSpecifier()); + } else if (isIdentifierName(lookahead) && !matchKeyword('default')) { + // import foo + specifiers.push(parseImportDefaultSpecifier()); + if (match(',')) { + lex(); + if (match('*')) { + // import foo, * as foo + specifiers.push(parseImportNamespaceSpecifier()); + } else if (match('{')) { + // import foo, {bar} + specifiers = specifiers.concat(parseNamedImports()); + } else { + throwUnexpectedToken(lookahead); + } + } + } else { + throwUnexpectedToken(lex()); + } + + if (!matchContextualKeyword('from')) { + throwError(lookahead.value ? + Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); + } + lex(); + src = parseModuleSpecifier(); + } + + consumeSemicolon(); + return node.finishImportDeclaration(specifiers, src); + } + + // ECMA-262 15.1 Scripts + + function parseScriptBody() { + var statement, body = [], token, directive, firstRestricted; + + while (startIndex < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + statement = parseStatementListItem(); + body.push(statement); + if (statement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (startIndex < length) { + statement = parseStatementListItem(); + /* istanbul ignore if */ + if (typeof statement === 'undefined') { + break; + } + body.push(statement); + } + return body; + } + + function parseProgram() { + var body, node; + + peek(); + node = new Node(); + + body = parseScriptBody(); + return node.finishProgram(body, state.sourceType); + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (entry.regex) { + token.regex = { + pattern: entry.regex.pattern, + flags: entry.regex.flags + }; + } + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function tokenize(code, options, delegate) { + var toString, + tokens; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + startIndex = index; + startLineNumber = lineNumber; + startLineStart = lineStart; + length = source.length; + lookahead = null; + state = { + allowIn: true, + allowYield: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1, + curlyStack: [] + }; + + extra = {}; + + // Options matching. + options = options || {}; + + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenValues = []; + extra.tokenize = true; + extra.delegate = delegate; + + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; + + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; + } + + lex(); + while (lookahead.type !== Token.EOF) { + try { + lex(); + } catch (lexError) { + if (extra.errors) { + recordError(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; + } + } + } + + tokens = extra.tokens; + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + return tokens; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + startIndex = index; + startLineNumber = lineNumber; + startLineStart = lineStart; + length = source.length; + lookahead = null; + state = { + allowIn: true, + allowYield: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1, + curlyStack: [], + sourceType: 'script' + }; + strict = false; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; + + if (extra.loc && options.source !== null && options.source !== undefined) { + extra.source = toString(options.source); + } + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + if (extra.attachComment) { + extra.range = true; + extra.comments = []; + extra.bottomRightStack = []; + extra.trailingComments = []; + extra.leadingComments = []; + } + if (options.sourceType === 'module') { + // very restrictive condition for now + state.sourceType = options.sourceType; + strict = true; + } + } + + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + + return program; + } + + // Sync with *.json manifests. + exports.version = '2.7.3'; + + exports.tokenize = tokenize; + + exports.parse = parse; + + // Deep copy. + /* istanbul ignore next */ + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/node_modules/svgo/node_modules/esprima/package.json b/node_modules/svgo/node_modules/esprima/package.json new file mode 100644 index 00000000..f2d59120 --- /dev/null +++ b/node_modules/svgo/node_modules/esprima/package.json @@ -0,0 +1,99 @@ +{ + "name": "esprima", + "description": "ECMAScript parsing infrastructure for multipurpose analysis", + "homepage": "http://esprima.org", + "main": "esprima.js", + "bin": { + "esparse": "./bin/esparse.js", + "esvalidate": "./bin/esvalidate.js" + }, + "version": "2.7.3", + "files": [ + "bin", + "unit-tests.js", + "esprima.js" + ], + "engines": { + "node": ">=0.10.0" + }, + "author": { + "name": "Ariya Hidayat", + "email": "ariya.hidayat@gmail.com" + }, + "maintainers": [ + { + "name": "Ariya Hidayat", + "email": "ariya.hidayat@gmail.com", + "web": "http://ariya.ofilabs.com" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/jquery/esprima.git" + }, + "bugs": { + "url": "https://github.com/jquery/esprima/issues" + }, + "license": "BSD-2-Clause", + "devDependencies": { + "codecov.io": "~0.1.6", + "escomplex-js": "1.2.0", + "eslint": "~1.7.2", + "everything.js": "~1.0.3", + "glob": "^5.0.15", + "istanbul": "~0.4.0", + "jscs": "~2.3.5", + "json-diff": "~0.3.1", + "karma": "^0.13.11", + "karma-chrome-launcher": "^0.2.1", + "karma-detect-browsers": "^2.0.2", + "karma-firefox-launcher": "^0.1.6", + "karma-ie-launcher": "^0.2.0", + "karma-mocha": "^0.2.0", + "karma-safari-launcher": "^0.1.1", + "karma-sauce-launcher": "^0.2.14", + "lodash": "^3.10.0", + "mocha": "^2.3.3", + "node-tick-processor": "~0.0.2", + "regenerate": "~1.2.1", + "temp": "~0.8.3", + "unicode-7.0.0": "~0.1.5" + }, + "keywords": [ + "ast", + "ecmascript", + "javascript", + "parser", + "syntax" + ], + "scripts": { + "check-version": "node test/check-version.js", + "jscs": "jscs -p crockford esprima.js && jscs -p crockford test/*.js", + "eslint": "node node_modules/eslint/bin/eslint.js -c .lintrc esprima.js", + "complexity": "node test/check-complexity.js", + "static-analysis": "npm run check-version && npm run jscs && npm run eslint && npm run complexity", + "unit-tests": "node test/unit-tests.js", + "grammar-tests": "node test/grammar-tests.js", + "regression-tests": "node test/regression-tests.js", + "all-tests": "npm run generate-fixtures && npm run unit-tests && npm run grammar-tests && npm run regression-tests", + "generate-fixtures": "node tools/generate-fixtures.js", + "browser-tests": "npm run generate-fixtures && cd test && karma start --single-run", + "saucelabs-evergreen": "cd test && karma start saucelabs-evergreen.conf.js", + "saucelabs-safari": "cd test && karma start saucelabs-safari.conf.js", + "saucelabs-ie": "cd test && karma start saucelabs-ie.conf.js", + "analyze-coverage": "istanbul cover test/unit-tests.js", + "check-coverage": "istanbul check-coverage --statement 100 --branch 100 --function 100", + "dynamic-analysis": "npm run analyze-coverage && npm run check-coverage", + "test": "npm run all-tests && npm run static-analysis && npm run dynamic-analysis", + "profile": "node --prof test/profile.js && mv isolate*.log v8.log && node-tick-processor", + "benchmark": "node test/benchmarks.js", + "benchmark-quick": "node test/benchmarks.js quick", + "codecov" : "istanbul report cobertura && codecov < ./coverage/cobertura-coverage.xml", + "downstream": "node test/downstream.js", + "travis": "npm test", + "circleci": "npm test && npm run codecov && npm run downstream", + "appveyor": "npm run all-tests && npm run browser-tests && npm run dynamic-analysis", + "droneio": "npm test && npm run saucelabs-evergreen && npm run saucelabs-ie && npm run saucelabs-safari", + "generate-regex": "node tools/generate-identifier-regex.js" + } +} diff --git a/node_modules/svgo/node_modules/js-yaml/.bin/js-yaml b/node_modules/svgo/node_modules/js-yaml/.bin/js-yaml new file mode 120000 index 00000000..978fe612 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/.bin/js-yaml @@ -0,0 +1 @@ +../bin/js-yaml.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/js-yaml/CHANGELOG.md b/node_modules/svgo/node_modules/js-yaml/CHANGELOG.md new file mode 100644 index 00000000..103b1bbc --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/CHANGELOG.md @@ -0,0 +1,409 @@ +3.7.0 / 2016-11-12 +------------------ + +- Fix parsing of quotes followed by newlines (#304, thanks to @dplepage). +- Support polymorphism for tags (#300, thanks to @monken). + + +3.6.1 / 2016-05-11 +------------------ + +- Fix output cut on a pipe, #286. + + +3.6.0 / 2016-04-16 +------------------ + +- Dumper rewrite, fix multiple bugs with trailing `\n`. + Big thanks to @aepsilon! +- Loader: fix leading/trailing newlines in block scalars, @aepsilon. + + +3.5.5 / 2016-03-17 +------------------ + +- Date parse fix: don't allow dates with on digit in month and day, #268. + + +3.5.4 / 2016-03-09 +------------------ + +- `noCompatMode` for dumper, to disable quoting YAML 1.1 values. + + +3.5.3 / 2016-02-11 +------------------ + +- Maintenance release. + + +3.5.2 / 2016-01-11 +------------------ + +- Maintenance: missed comma in bower config. + + +3.5.1 / 2016-01-11 +------------------ + +- Removed `inherit` dependency, #239. +- Better browserify workaround for esprima load. +- Demo rewrite. + + +3.5.0 / 2016-01-10 +------------------ + +- Dumper. Fold strings only, #217. +- Dumper. `norefs` option, to clone linked objects, #229. +- Loader. Throw a warning for duplicate keys, #166. +- Improved browserify support (mark `esprima` & `Buffer` excluded). + + +3.4.6 / 2015-11-26 +------------------ + +- Use standalone `inherit` to keep browserified files clear. + + +3.4.5 / 2015-11-23 +------------------ + +- Added `lineWidth` option to dumper. + + +3.4.4 / 2015-11-21 +------------------ + +- Fixed floats dump (missed dot for scientific format), #220. +- Allow non-printable characters inside quoted scalars, #192. + + +3.4.3 / 2015-10-10 +------------------ + +- Maintenance release - deps bump (esprima, argparse). + + +3.4.2 / 2015-09-09 +------------------ + +- Fixed serialization of duplicated entries in sequences, #205. + Thanks to @vogelsgesang. + + +3.4.1 / 2015-09-05 +------------------ + +- Fixed stacktrace handling in generated errors, for browsers (FF/IE). + + +3.4.0 / 2015-08-23 +------------------ + +- Fixed multiline keys dump, #197. Thanks to @tcr. +- Don't throw on warnongs anymore. Use `onWarning` option to catch. +- Throw error on unknown tags (was warning before). +- Fixed heading line breaks in some scalars (regression). +- Reworked internals of error class. + + +3.3.1 / 2015-05-13 +------------------ + +- Added `.sortKeys` dumper option, thanks to @rjmunro. +- Fixed astral characters support, #191. + + +3.3.0 / 2015-04-26 +------------------ + +- Significantly improved long strings formatting in dumper, thanks to @isaacs. +- Strip BOM if exists. + + +3.2.7 / 2015-02-19 +------------------ + +- Maintenance release. +- Updated dependencies. +- HISTORY.md -> CHANGELOG.md + + +3.2.6 / 2015-02-07 +------------------ + +- Fixed encoding of UTF-16 surrogate pairs. (e.g. "\U0001F431" CAT FACE). +- Fixed demo dates dump (#113, thanks to @Hypercubed). + + +3.2.5 / 2014-12-28 +------------------ + +- Fixed resolving of all built-in types on empty nodes. +- Fixed invalid warning on empty lines within quoted scalars and flow collections. +- Fixed bug: Tag on an empty node didn't resolve in some cases. + + +3.2.4 / 2014-12-19 +------------------ + +- Fixed resolving of !!null tag on an empty node. + + +3.2.3 / 2014-11-08 +------------------ + +- Implemented dumping of objects with circular and cross references. +- Partially fixed aliasing of constructed objects. (see issue #141 for details) + + +3.2.2 / 2014-09-07 +------------------ + +- Fixed infinite loop on unindented block scalars. +- Rewritten base64 encode/decode in binary type, to keep code licence clear. + + +3.2.1 / 2014-08-24 +------------------ + +- Nothig new. Just fix npm publish error. + + +3.2.0 / 2014-08-24 +------------------ + +- Added input piping support to CLI. +- Fixed typo, that could cause hand on initial indent (#139). + + +3.1.0 / 2014-07-07 +------------------ + +- 1.5x-2x speed boost. +- Removed deprecated `require('xxx.yml')` support. +- Significant code cleanup and refactoring. +- Internal API changed. If you used custom types - see updated examples. + Others are not affected. +- Even if the input string has no trailing line break character, + it will be parsed as if it has one. +- Added benchmark scripts. +- Moved bower files to /dist folder +- Bugfixes. + + +3.0.2 / 2014-02-27 +------------------ + +- Fixed bug: "constructor" string parsed as `null`. + + +3.0.1 / 2013-12-22 +------------------ + +- Fixed parsing of literal scalars. (issue #108) +- Prevented adding unnecessary spaces in object dumps. (issue #68) +- Fixed dumping of objects with very long (> 1024 in length) keys. + + +3.0.0 / 2013-12-16 +------------------ + +- Refactored code. Changed API for custom types. +- Removed output colors in CLI, dump json by default. +- Removed big dependencies from browser version (esprima, buffer) + - load `esprima` manually, if !!js/function needed + - !!bin now returns Array in browser +- AMD support. +- Don't quote dumped strings because of `-` & `?` (if not first char). +- __Deprecated__ loading yaml files via `require()`, as not recommended + behaviour for node. + + +2.1.3 / 2013-10-16 +------------------ + +- Fix wrong loading of empty block scalars. + + +2.1.2 / 2013-10-07 +------------------ + +- Fix unwanted line breaks in folded scalars. + + +2.1.1 / 2013-10-02 +------------------ + +- Dumper now respects deprecated booleans syntax from YAML 1.0/1.1 +- Fixed reader bug in JSON-like sequences/mappings. + + +2.1.0 / 2013-06-05 +------------------ + +- Add standard YAML schemas: Failsafe (`FAILSAFE_SCHEMA`), + JSON (`JSON_SCHEMA`) and Core (`CORE_SCHEMA`). +- Rename `DEFAULT_SCHEMA` to `DEFAULT_FULL_SCHEMA` + and `SAFE_SCHEMA` to `DEFAULT_SAFE_SCHEMA`. +- Bug fix: export `NIL` constant from the public interface. +- Add `skipInvalid` dumper option. +- Use `safeLoad` for `require` extension. + + +2.0.5 / 2013-04-26 +------------------ + +- Close security issue in !!js/function constructor. + Big thanks to @nealpoole for security audit. + + +2.0.4 / 2013-04-08 +------------------ + +- Updated .npmignore to reduce package size + + +2.0.3 / 2013-02-26 +------------------ + +- Fixed dumping of empty arrays ans objects. ([] and {} instead of null) + + +2.0.2 / 2013-02-15 +------------------ + +- Fixed input validation: tabs are printable characters. + + +2.0.1 / 2013-02-09 +------------------ + +- Fixed error, when options not passed to function cass + + +2.0.0 / 2013-02-09 +------------------ + +- Full rewrite. New architecture. Fast one-stage parsing. +- Changed custom types API. +- Added YAML dumper. + + +1.0.3 / 2012-11-05 +------------------ + +- Fixed utf-8 files loading. + + +1.0.2 / 2012-08-02 +------------------ + +- Pull out hand-written shims. Use ES5-Shims for old browsers support. See #44. +- Fix timstamps incorectly parsed in local time when no time part specified. + + +1.0.1 / 2012-07-07 +------------------ + +- Fixes `TypeError: 'undefined' is not an object` under Safari. Thanks Phuong. +- Fix timestamps incorrectly parsed in local time. Thanks @caolan. Closes #46. + + +1.0.0 / 2012-07-01 +------------------ + +- `y`, `yes`, `n`, `no`, `on`, `off` are not converted to Booleans anymore. + Fixes #42. +- `require(filename)` now returns a single document and throws an Error if + file contains more than one document. +- CLI was merged back from js-yaml.bin + + +0.3.7 / 2012-02-28 +------------------ + +- Fix export of `addConstructor()`. Closes #39. + + +0.3.6 / 2012-02-22 +------------------ + +- Removed AMD parts - too buggy to use. Need help to rewrite from scratch +- Removed YUI compressor warning (renamed `double` variable). Closes #40. + + +0.3.5 / 2012-01-10 +------------------ + +- Workagound for .npmignore fuckup under windows. Thanks to airportyh. + + +0.3.4 / 2011-12-24 +------------------ + +- Fixes str[] for oldIEs support. +- Adds better has change support for browserified demo. +- improves compact output of Error. Closes #33. + + +0.3.3 / 2011-12-20 +------------------ + +- jsyaml executable moved to separate module. +- adds `compact` stringification of Errors. + + +0.3.2 / 2011-12-16 +------------------ + +- Fixes ug with block style scalars. Closes #26. +- All sources are passing JSLint now. +- Fixes bug in Safari. Closes #28. +- Fixes bug in Opers. Closes #29. +- Improves browser support. Closes #20. +- Added jsyaml executable. +- Added !!js/function support. Closes #12. + + +0.3.1 / 2011-11-18 +------------------ + +- Added AMD support for browserified version. +- Wrapped browserified js-yaml into closure. +- Fixed the resolvement of non-specific tags. Closes #17. +- Added permalinks for online demo YAML snippets. Now we have YPaste service, lol. +- Added !!js/regexp and !!js/undefined types. Partially solves #12. +- Fixed !!set mapping. +- Fixed month parse in dates. Closes #19. + + +0.3.0 / 2011-11-09 +------------------ + +- Removed JS.Class dependency. Closes #3. +- Added browserified version. Closes #13. +- Added live demo of browserified version. +- Ported some of the PyYAML tests. See #14. +- Fixed timestamp bug when fraction was given. + + +0.2.2 / 2011-11-06 +------------------ + +- Fixed crash on docs without ---. Closes #8. +- Fixed miltiline string parse +- Fixed tests/comments for using array as key + + +0.2.1 / 2011-11-02 +------------------ + +- Fixed short file read (<4k). Closes #9. + + +0.2.0 / 2011-11-02 +------------------ + +- First public release diff --git a/node_modules/svgo/node_modules/js-yaml/LICENSE b/node_modules/svgo/node_modules/js-yaml/LICENSE new file mode 100644 index 00000000..09d3a29e --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/LICENSE @@ -0,0 +1,21 @@ +(The MIT License) + +Copyright (C) 2011-2015 by Vitaly Puzrin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/svgo/node_modules/js-yaml/README.md b/node_modules/svgo/node_modules/js-yaml/README.md new file mode 100644 index 00000000..45c35020 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/README.md @@ -0,0 +1,295 @@ +JS-YAML - YAML 1.2 parser / writer for JavaScript +================================================= + +[](https://travis-ci.org/nodeca/js-yaml) +[](https://www.npmjs.org/package/js-yaml) + +__[Online Demo](http://nodeca.github.com/js-yaml/)__ + + +This is an implementation of [YAML](http://yaml.org/), a human friendly data +serialization language. Started as [PyYAML](http://pyyaml.org/) port, it was +completely rewritten from scratch. Now it's very fast, and supports 1.2 spec. + + +Installation +------------ + +### YAML module for node.js + +``` +npm install js-yaml +``` + + +### CLI executable + +If you want to inspect your YAML files from CLI, install js-yaml globally: + +``` +npm install -g js-yaml +``` + +#### Usage + +``` +usage: js-yaml [-h] [-v] [-c] [-t] file + +Positional arguments: + file File with YAML document(s) + +Optional arguments: + -h, --help Show this help message and exit. + -v, --version Show program's version number and exit. + -c, --compact Display errors in compact mode + -t, --trace Show stack trace on error +``` + + +### Bundled YAML library for browsers + +``` html +<!-- esprima required only for !!js/function --> +<script src="esprima.js"></script> +<script src="js-yaml.min.js"></script> +<script type="text/javascript"> +var doc = jsyaml.load('greeting: hello\nname: world'); +</script> +``` + +Browser support was done mostly for online demo. If you find any errors - feel +free to send pull requests with fixes. Also note, that IE and other old browsers +needs [es5-shims](https://github.com/kriskowal/es5-shim) to operate. + +Notes: + +1. We have no resources to support browserified version. Don't expect it to be + well tested. Don't expect fast fixes if something goes wrong there. +2. `!!js/function` in browser bundle will not work by default. If you really need + it - load `esprima` parser first (via amd or directly). +3. `!!bin` in browser will return `Array`, because browsers do not support + node.js `Buffer` and adding Buffer shims is completely useless on practice. + + +API +--- + +Here we cover the most 'useful' methods. If you need advanced details (creating +your own tags), see [wiki](https://github.com/nodeca/js-yaml/wiki) and +[examples](https://github.com/nodeca/js-yaml/tree/master/examples) for more +info. + +``` javascript +yaml = require('js-yaml'); +fs = require('fs'); + +// Get document, or throw exception on error +try { + var doc = yaml.safeLoad(fs.readFileSync('/home/ixti/example.yml', 'utf8')); + console.log(doc); +} catch (e) { + console.log(e); +} +``` + + +### safeLoad (string [ , options ]) + +**Recommended loading way.** Parses `string` as single YAML document. Returns a JavaScript +object or throws `YAMLException` on error. By default, does not support regexps, +functions and undefined. This method is safe for untrusted data. + +options: + +- `filename` _(default: null)_ - string to be used as a file path in + error/warning messages. +- `onWarning` _(default: null)_ - function to call on warning messages. + Loader will throw on warnings if this function is not provided. +- `schema` _(default: `DEFAULT_SAFE_SCHEMA`)_ - specifies a schema to use. + - `FAILSAFE_SCHEMA` - only strings, arrays and plain objects: + http://www.yaml.org/spec/1.2/spec.html#id2802346 + - `JSON_SCHEMA` - all JSON-supported types: + http://www.yaml.org/spec/1.2/spec.html#id2803231 + - `CORE_SCHEMA` - same as `JSON_SCHEMA`: + http://www.yaml.org/spec/1.2/spec.html#id2804923 + - `DEFAULT_SAFE_SCHEMA` - all supported YAML types, without unsafe ones + (`!!js/undefined`, `!!js/regexp` and `!!js/function`): + http://yaml.org/type/ + - `DEFAULT_FULL_SCHEMA` - all supported YAML types. +- `json` _(default: false)_ - compatibility with JSON.parse behaviour. If true, then duplicate keys in a mapping will override values rather than throwing an error. + +NOTE: This function **does not** understand multi-document sources, it throws +exception on those. + +NOTE: JS-YAML **does not** support schema-specific tag resolution restrictions. +So, JSON schema is not as strict as defined in the YAML specification. +It allows numbers in any notation, use `Null` and `NULL` as `null`, etc. +Core schema also has no such restrictions. It allows binary notation for integers. + + +### load (string [ , options ]) + +**Use with care with untrusted sources**. The same as `safeLoad()` but uses +`DEFAULT_FULL_SCHEMA` by default - adds some JavaScript-specific types: +`!!js/function`, `!!js/regexp` and `!!js/undefined`. For untrusted sources you +must additionally validate object structure, to avoid injections: + +``` javascript +var untrusted_code = '"toString": !<tag:yaml.org,2002:js/function> "function (){very_evil_thing();}"'; + +// I'm just converting that string, what could possibly go wrong? +require('js-yaml').load(untrusted_code) + '' +``` + + +### safeLoadAll (string, iterator [ , options ]) + +Same as `safeLoad()`, but understands multi-document sources and apply +`iterator` to each document. + +``` javascript +var yaml = require('js-yaml'); + +yaml.safeLoadAll(data, function (doc) { + console.log(doc); +}); +``` + + +### loadAll (string, iterator [ , options ]) + +Same as `safeLoadAll()` but uses `DEFAULT_FULL_SCHEMA` by default. + + +### safeDump (object [ , options ]) + +Serializes `object` as YAML document. Uses `DEFAULT_SAFE_SCHEMA`, so it will +throw exception if you try to dump regexps or functions. However, you can +disable exceptions by `skipInvalid` option. + +options: + +- `indent` _(default: 2)_ - indentation width to use (in spaces). +- `skipInvalid` _(default: false)_ - do not throw on invalid types (like function + in the safe schema) and skip pairs and single values with such types. +- `flowLevel` (default: -1) - specifies level of nesting, when to switch from + block to flow style for collections. -1 means block style everwhere +- `styles` - "tag" => "style" map. Each tag may have own set of styles. +- `schema` _(default: `DEFAULT_SAFE_SCHEMA`)_ specifies a schema to use. +- `sortKeys` _(default: `false`)_ - if `true`, sort keys when dumping YAML. If a + function, use the function to sort the keys. +- `lineWidth` _(default: `80`)_ - set max line width. +- `noRefs` _(default: `false`)_ - if `true`, don't convert duplicate objects into references +- `noCompatMode` _(default: `false`)_ - if `true` don't try to be compatible with older + yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1 + +styles: + +``` none +!!null + "canonical" => "~" + +!!int + "binary" => "0b1", "0b101010", "0b1110001111010" + "octal" => "01", "052", "016172" + "decimal" => "1", "42", "7290" + "hexadecimal" => "0x1", "0x2A", "0x1C7A" + +!!null, !!bool, !!float + "lowercase" => "null", "true", "false", ".nan", '.inf' + "uppercase" => "NULL", "TRUE", "FALSE", ".NAN", '.INF' + "camelcase" => "Null", "True", "False", ".NaN", '.Inf' +``` + +By default, !!int uses `decimal`, and !!null, !!bool, !!float use `lowercase`. + + + +### dump (object [ , options ]) + +Same as `safeDump()` but without limits (uses `DEFAULT_FULL_SCHEMA` by default). + + +Supported YAML types +-------------------- + +The list of standard YAML tags and corresponding JavaScipt types. See also +[YAML tag discussion](http://pyyaml.org/wiki/YAMLTagDiscussion) and +[YAML types repository](http://yaml.org/type/). + +``` +!!null '' # null +!!bool 'yes' # bool +!!int '3...' # number +!!float '3.14...' # number +!!binary '...base64...' # buffer +!!timestamp 'YYYY-...' # date +!!omap [ ... ] # array of key-value pairs +!!pairs [ ... ] # array or array pairs +!!set { ... } # array of objects with given keys and null values +!!str '...' # string +!!seq [ ... ] # array +!!map { ... } # object +``` + +**JavaScript-specific tags** + +``` +!!js/regexp /pattern/gim # RegExp +!!js/undefined '' # Undefined +!!js/function 'function () {...}' # Function +``` + +Caveats +------- + +Note, that you use arrays or objects as key in JS-YAML. JS does not allow objects +or array as keys, and stringifies (by calling .toString method) them at the +moment of adding them. + +``` yaml +--- +? [ foo, bar ] +: - baz +? { foo: bar } +: - baz + - baz +``` + +``` javascript +{ "foo,bar": ["baz"], "[object Object]": ["baz", "baz"] } +``` + +Also, reading of properties on implicit block mapping keys is not supported yet. +So, the following YAML document cannot be loaded. + +``` yaml +&anchor foo: + foo: bar + *anchor: duplicate key + baz: bat + *anchor: duplicate key +``` + + +Breaking changes in 2.x.x -> 3.x.x +---------------------------------- + +If you have not used __custom__ tags or loader classes and not loaded yaml +files via `require()` - no changes needed. Just upgrade library. + +Otherwise, you should: + +1. Replace all occurences of `require('xxxx.yml')` by `fs.readFileSync()` + + `yaml.safeLoad()`. +2. rewrite your custom tags constructors and custom loader + classes, to conform new API. See + [examples](https://github.com/nodeca/js-yaml/tree/master/examples) and + [wiki](https://github.com/nodeca/js-yaml/wiki) for details. + + +License +------- + +View the [LICENSE](https://github.com/nodeca/js-yaml/blob/master/LICENSE) file +(MIT). diff --git a/node_modules/svgo/node_modules/js-yaml/bin/js-yaml.js b/node_modules/svgo/node_modules/js-yaml/bin/js-yaml.js new file mode 100755 index 00000000..e79186be --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/bin/js-yaml.js @@ -0,0 +1,132 @@ +#!/usr/bin/env node + + +'use strict'; + +/*eslint-disable no-console*/ + + +// stdlib +var fs = require('fs'); + + +// 3rd-party +var argparse = require('argparse'); + + +// internal +var yaml = require('..'); + + +//////////////////////////////////////////////////////////////////////////////// + + +var cli = new argparse.ArgumentParser({ + prog: 'js-yaml', + version: require('../package.json').version, + addHelp: true +}); + + +cli.addArgument([ '-c', '--compact' ], { + help: 'Display errors in compact mode', + action: 'storeTrue' +}); + + +// deprecated (not needed after we removed output colors) +// option suppressed, but not completely removed for compatibility +cli.addArgument([ '-j', '--to-json' ], { + help: argparse.Const.SUPPRESS, + dest: 'json', + action: 'storeTrue' +}); + + +cli.addArgument([ '-t', '--trace' ], { + help: 'Show stack trace on error', + action: 'storeTrue' +}); + +cli.addArgument([ 'file' ], { + help: 'File to read, utf-8 encoded without BOM', + nargs: '?', + defaultValue: '-' +}); + + +//////////////////////////////////////////////////////////////////////////////// + + +var options = cli.parseArgs(); + + +//////////////////////////////////////////////////////////////////////////////// + +function readFile(filename, encoding, callback) { + if (options.file === '-') { + // read from stdin + + var chunks = []; + + process.stdin.on('data', function (chunk) { + chunks.push(chunk); + }); + + process.stdin.on('end', function () { + return callback(null, Buffer.concat(chunks).toString(encoding)); + }); + } else { + fs.readFile(filename, encoding, callback); + } +} + +readFile(options.file, 'utf8', function (error, input) { + var output, isYaml; + + if (error) { + if (error.code === 'ENOENT') { + console.error('File not found: ' + options.file); + process.exit(2); + } + + console.error( + options.trace && error.stack || + error.message || + String(error)); + + process.exit(1); + } + + try { + output = JSON.parse(input); + isYaml = false; + } catch (err) { + if (err instanceof SyntaxError) { + try { + output = []; + yaml.loadAll(input, function (doc) { output.push(doc); }, {}); + isYaml = true; + + if (output.length === 0) output = null; + else if (output.length === 1) output = output[0]; + + } catch (e) { + if (options.trace && err.stack) console.error(e.stack); + else console.error(e.toString(options.compact)); + + process.exit(1); + } + } else { + console.error( + options.trace && err.stack || + err.message || + String(err)); + + process.exit(1); + } + } + + if (isYaml) console.log(JSON.stringify(output, null, ' ')); + else console.log(yaml.dump(output)); +}); diff --git a/node_modules/svgo/node_modules/js-yaml/dist/js-yaml.js b/node_modules/svgo/node_modules/js-yaml/dist/js-yaml.js new file mode 100644 index 00000000..49cb23c9 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/dist/js-yaml.js @@ -0,0 +1,3855 @@ +/* js-yaml 3.7.0 https://github.com/nodeca/js-yaml */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsyaml = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ +'use strict'; + + +var loader = require('./js-yaml/loader'); +var dumper = require('./js-yaml/dumper'); + + +function deprecated(name) { + return function () { + throw new Error('Function ' + name + ' is deprecated and cannot be used.'); + }; +} + + +module.exports.Type = require('./js-yaml/type'); +module.exports.Schema = require('./js-yaml/schema'); +module.exports.FAILSAFE_SCHEMA = require('./js-yaml/schema/failsafe'); +module.exports.JSON_SCHEMA = require('./js-yaml/schema/json'); +module.exports.CORE_SCHEMA = require('./js-yaml/schema/core'); +module.exports.DEFAULT_SAFE_SCHEMA = require('./js-yaml/schema/default_safe'); +module.exports.DEFAULT_FULL_SCHEMA = require('./js-yaml/schema/default_full'); +module.exports.load = loader.load; +module.exports.loadAll = loader.loadAll; +module.exports.safeLoad = loader.safeLoad; +module.exports.safeLoadAll = loader.safeLoadAll; +module.exports.dump = dumper.dump; +module.exports.safeDump = dumper.safeDump; +module.exports.YAMLException = require('./js-yaml/exception'); + +// Deprecated schema names from JS-YAML 2.0.x +module.exports.MINIMAL_SCHEMA = require('./js-yaml/schema/failsafe'); +module.exports.SAFE_SCHEMA = require('./js-yaml/schema/default_safe'); +module.exports.DEFAULT_SCHEMA = require('./js-yaml/schema/default_full'); + +// Deprecated functions from JS-YAML 1.x.x +module.exports.scan = deprecated('scan'); +module.exports.parse = deprecated('parse'); +module.exports.compose = deprecated('compose'); +module.exports.addConstructor = deprecated('addConstructor'); + +},{"./js-yaml/dumper":3,"./js-yaml/exception":4,"./js-yaml/loader":5,"./js-yaml/schema":7,"./js-yaml/schema/core":8,"./js-yaml/schema/default_full":9,"./js-yaml/schema/default_safe":10,"./js-yaml/schema/failsafe":11,"./js-yaml/schema/json":12,"./js-yaml/type":13}],2:[function(require,module,exports){ +'use strict'; + + +function isNothing(subject) { + return (typeof subject === 'undefined') || (subject === null); +} + + +function isObject(subject) { + return (typeof subject === 'object') && (subject !== null); +} + + +function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + + return [ sequence ]; +} + + +function extend(target, source) { + var index, length, key, sourceKeys; + + if (source) { + sourceKeys = Object.keys(source); + + for (index = 0, length = sourceKeys.length; index < length; index += 1) { + key = sourceKeys[index]; + target[key] = source[key]; + } + } + + return target; +} + + +function repeat(string, count) { + var result = '', cycle; + + for (cycle = 0; cycle < count; cycle += 1) { + result += string; + } + + return result; +} + + +function isNegativeZero(number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); +} + + +module.exports.isNothing = isNothing; +module.exports.isObject = isObject; +module.exports.toArray = toArray; +module.exports.repeat = repeat; +module.exports.isNegativeZero = isNegativeZero; +module.exports.extend = extend; + +},{}],3:[function(require,module,exports){ +'use strict'; + +/*eslint-disable no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var DEFAULT_FULL_SCHEMA = require('./schema/default_full'); +var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe'); + +var _toString = Object.prototype.toString; +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +var CHAR_TAB = 0x09; /* Tab */ +var CHAR_LINE_FEED = 0x0A; /* LF */ +var CHAR_SPACE = 0x20; /* Space */ +var CHAR_EXCLAMATION = 0x21; /* ! */ +var CHAR_DOUBLE_QUOTE = 0x22; /* " */ +var CHAR_SHARP = 0x23; /* # */ +var CHAR_PERCENT = 0x25; /* % */ +var CHAR_AMPERSAND = 0x26; /* & */ +var CHAR_SINGLE_QUOTE = 0x27; /* ' */ +var CHAR_ASTERISK = 0x2A; /* * */ +var CHAR_COMMA = 0x2C; /* , */ +var CHAR_MINUS = 0x2D; /* - */ +var CHAR_COLON = 0x3A; /* : */ +var CHAR_GREATER_THAN = 0x3E; /* > */ +var CHAR_QUESTION = 0x3F; /* ? */ +var CHAR_COMMERCIAL_AT = 0x40; /* @ */ +var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ +var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ +var CHAR_GRAVE_ACCENT = 0x60; /* ` */ +var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ +var CHAR_VERTICAL_LINE = 0x7C; /* | */ +var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + +var ESCAPE_SEQUENCES = {}; + +ESCAPE_SEQUENCES[0x00] = '\\0'; +ESCAPE_SEQUENCES[0x07] = '\\a'; +ESCAPE_SEQUENCES[0x08] = '\\b'; +ESCAPE_SEQUENCES[0x09] = '\\t'; +ESCAPE_SEQUENCES[0x0A] = '\\n'; +ESCAPE_SEQUENCES[0x0B] = '\\v'; +ESCAPE_SEQUENCES[0x0C] = '\\f'; +ESCAPE_SEQUENCES[0x0D] = '\\r'; +ESCAPE_SEQUENCES[0x1B] = '\\e'; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5C] = '\\\\'; +ESCAPE_SEQUENCES[0x85] = '\\N'; +ESCAPE_SEQUENCES[0xA0] = '\\_'; +ESCAPE_SEQUENCES[0x2028] = '\\L'; +ESCAPE_SEQUENCES[0x2029] = '\\P'; + +var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +]; + +function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; +} + +function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; +} + +function State(options) { + this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; + this.indent = Math.max(1, (options['indent'] || 2)); + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; +} + +function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); +} + +function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== 0xFEFF /* BOM */) + || (0x10000 <= c && c <= 0x10FFFF); +} + +// Simplified test for values allowed after the first character in plain style. +function isPlainSafe(c) { + // Uses a subset of nb-char - c-flow-indicator - ":" - "#" + // where nb-char ::= c-printable - b-char - c-byte-order-mark. + return isPrintable(c) && c !== 0xFEFF + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // - ":" - "#" + && c !== CHAR_COLON + && c !== CHAR_SHARP; +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + return isPrintable(c) && c !== 0xFEFF + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; +} + +var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { + var i; + var char; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(string.charCodeAt(0)) + && !isWhitespace(string.charCodeAt(string.length - 1)); + + if (singleLineOnly) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char); + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char); + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + return plain && !testAmbiguousType(string) + ? STYLE_PLAIN : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (string[0] === ' ' && indentPerLevel > 9) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar(state, string, level, iskey) { + state.dump = (function () { + if (string.length === 0) { + return "''"; + } + if (!state.noCompatMode && + DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) { + return "'" + string + "'"; + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) { + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string, lineWidth) + '"'; + default: + throw new YAMLException('impossible error: invalid scalar style'); + } + }()); +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader(string, indentPerLevel) { + var indentIndicator = (string[0] === ' ') ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; +} + +// (See the note for writeScalar.) +function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString(string) { + var result = ''; + var char; + var escapeSeq; + + for (var i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + escapeSeq = ESCAPE_SEQUENCES[char]; + result += !escapeSeq && isPrintable(char) + ? string[i] + : escapeSeq || encodeHex(char); + } + + return result; +} + +function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length; + + for (index = 0, length = object.length; index < length; index += 1) { + // Write only valid elements. + if (writeNode(state, level, object[index], false, false)) { + if (index !== 0) _result += ', '; + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; +} + +function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length; + + for (index = 0, length = object.length; index < length; index += 1) { + // Write only valid elements. + if (writeNode(state, level + 1, object[index], true, true)) { + if (!compact || index !== 0) { + _result += generateNextLine(state, level); + } + _result += '- ' + state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. +} + +function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (index !== 0) pairBuffer += ', '; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + ': '; + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; +} + +function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new YAMLException('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || index !== 0) { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. +} + +function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + state.tag = explicit ? type.tag : '?'; + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode(state, level, object, block, compact, iskey) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + writeBlockSequence(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey); + } + } else { + if (state.skipInvalid) return false; + throw new YAMLException('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + state.dump = '!<' + state.tag + '> ' + state.dump; + } + } + + return true; +} + +function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); +} + +function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } +} + +function dump(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + if (writeNode(state, 0, input, true, true)) return state.dump + '\n'; + + return ''; +} + +function safeDump(input, options) { + return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + +module.exports.dump = dump; +module.exports.safeDump = safeDump; + +},{"./common":2,"./exception":4,"./schema/default_full":9,"./schema/default_safe":10}],4:[function(require,module,exports){ +// YAML error class. http://stackoverflow.com/questions/8458984 +// +'use strict'; + +function YAMLException(reason, mark) { + // Super constructor + Error.call(this); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : ''); +} + + +// Inherit from Error +YAMLException.prototype = Object.create(Error.prototype); +YAMLException.prototype.constructor = YAMLException; + + +YAMLException.prototype.toString = function toString(compact) { + var result = this.name + ': '; + + result += this.reason || '(unknown reason)'; + + if (!compact && this.mark) { + result += ' ' + this.mark.toString(); + } + + return result; +}; + + +module.exports = YAMLException; + +},{}],5:[function(require,module,exports){ +'use strict'; + +/*eslint-disable max-len,no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var Mark = require('./mark'); +var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe'); +var DEFAULT_FULL_SCHEMA = require('./schema/default_full'); + + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + + +var CONTEXT_FLOW_IN = 1; +var CONTEXT_FLOW_OUT = 2; +var CONTEXT_BLOCK_IN = 3; +var CONTEXT_BLOCK_OUT = 4; + + +var CHOMPING_CLIP = 1; +var CHOMPING_STRIP = 2; +var CHOMPING_KEEP = 3; + + +var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + +function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); +} + +function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); +} + +function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); +} + +function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; +} + +function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; +} + +function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; +} + +function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; +} + +function simpleEscapeSequence(c) { + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; +} + +function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode(((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00); +} + +var simpleEscapeCheck = new Array(256); // integer, for fast access +var simpleEscapeMap = new Array(256); +for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); +} + + +function State(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; + this.onWarning = options['onWarning'] || null; + this.legacy = options['legacy'] || false; + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + +} + + +function generateError(state, message) { + return new YAMLException( + message, + new Mark(state.filename, state.input, state.position, state.line, (state.position - state.lineStart))); +} + +function throwError(state, message) { + throw generateError(state, message); +} + +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} + + +var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + state.tagMap[handle] = prefix; + } +}; + + +function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; + _position < _length; + _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } +} + +function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} + +function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode) { + var index, quantity; + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty.call(overridableKeys, keyNode) && + _hasOwnProperty.call(_result, keyNode)) { + throwError(state, 'duplicated mapping key'); + } + _result[keyNode] = valueNode; + delete overridableKeys[keyNode]; + } + + return _result; +} + +function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; +} + +function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; +} + +function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; +} + +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } +} + + +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; +} + +function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); +} + +function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); +} + +function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = {}, + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); +} + +function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; +} + +function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; +} + +function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = {}, + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else { + break; // Reading is done. Go to the epilogue. + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if (state.lineIndent > nodeIndent && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; +} + +function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; +} + +function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; +} + +function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!state.anchorMap.hasOwnProperty(alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; +} + +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this<parent + atNewLine = false, + hasContent = false, + typeIndex, + typeQuantity, + type, + flowIndent, + blockIndent; + + if (state.listener !== null) { + state.listener('open', state); + } + + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + + allowBlockStyles = allowBlockScalars = allowBlockCollections = + CONTEXT_BLOCK_OUT === nodeContext || + CONTEXT_BLOCK_IN === nodeContext; + + if (allowToSeek) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag !== null && state.tag !== '!') { + if (state.tag === '?') { + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; + typeIndex < typeQuantity; + typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only assigned to plain scalars. So, it isn't + // needed to check for 'kind' conformity. + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} + +function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = {}; + state.anchorMap = {}; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } +} + + +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State(input, options); + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; +} + + +function loadAll(input, iterator, options) { + var documents = loadDocuments(input, options), index, length; + + for (index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } +} + + +function load(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new YAMLException('expected a single document in the stream, but found more'); +} + + +function safeLoadAll(input, output, options) { + loadAll(input, output, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + + +function safeLoad(input, options) { + return load(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + + +module.exports.loadAll = loadAll; +module.exports.load = load; +module.exports.safeLoadAll = safeLoadAll; +module.exports.safeLoad = safeLoad; + +},{"./common":2,"./exception":4,"./mark":6,"./schema/default_full":9,"./schema/default_safe":10}],6:[function(require,module,exports){ +'use strict'; + + +var common = require('./common'); + + +function Mark(name, buffer, position, line, column) { + this.name = name; + this.buffer = buffer; + this.position = position; + this.line = line; + this.column = column; +} + + +Mark.prototype.getSnippet = function getSnippet(indent, maxLength) { + var head, start, tail, end, snippet; + + if (!this.buffer) return null; + + indent = indent || 4; + maxLength = maxLength || 75; + + head = ''; + start = this.position; + + while (start > 0 && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(start - 1)) === -1) { + start -= 1; + if (this.position - start > (maxLength / 2 - 1)) { + head = ' ... '; + start += 5; + break; + } + } + + tail = ''; + end = this.position; + + while (end < this.buffer.length && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(end)) === -1) { + end += 1; + if (end - this.position > (maxLength / 2 - 1)) { + tail = ' ... '; + end -= 5; + break; + } + } + + snippet = this.buffer.slice(start, end); + + return common.repeat(' ', indent) + head + snippet + tail + '\n' + + common.repeat(' ', indent + this.position - start + head.length) + '^'; +}; + + +Mark.prototype.toString = function toString(compact) { + var snippet, where = ''; + + if (this.name) { + where += 'in "' + this.name + '" '; + } + + where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1); + + if (!compact) { + snippet = this.getSnippet(); + + if (snippet) { + where += ':\n' + snippet; + } + } + + return where; +}; + + +module.exports = Mark; + +},{"./common":2}],7:[function(require,module,exports){ +'use strict'; + +/*eslint-disable max-len*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var Type = require('./type'); + + +function compileList(schema, name, result) { + var exclude = []; + + schema.include.forEach(function (includedSchema) { + result = compileList(includedSchema, name, result); + }); + + schema[name].forEach(function (currentType) { + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) { + exclude.push(previousIndex); + } + }); + + result.push(currentType); + }); + + return result.filter(function (type, index) { + return exclude.indexOf(index) === -1; + }); +} + + +function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {} + }, index, length; + + function collectType(type) { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; +} + + +function Schema(definition) { + this.include = definition.include || []; + this.implicit = definition.implicit || []; + this.explicit = definition.explicit || []; + + this.implicit.forEach(function (type) { + if (type.loadKind && type.loadKind !== 'scalar') { + throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + }); + + this.compiledImplicit = compileList(this, 'implicit', []); + this.compiledExplicit = compileList(this, 'explicit', []); + this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit); +} + + +Schema.DEFAULT = null; + + +Schema.create = function createSchema() { + var schemas, types; + + switch (arguments.length) { + case 1: + schemas = Schema.DEFAULT; + types = arguments[0]; + break; + + case 2: + schemas = arguments[0]; + types = arguments[1]; + break; + + default: + throw new YAMLException('Wrong number of arguments for Schema.create function'); + } + + schemas = common.toArray(schemas); + types = common.toArray(types); + + if (!schemas.every(function (schema) { return schema instanceof Schema; })) { + throw new YAMLException('Specified list of super schemas (or a single Schema object) contains a non-Schema object.'); + } + + if (!types.every(function (type) { return type instanceof Type; })) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + return new Schema({ + include: schemas, + explicit: types + }); +}; + + +module.exports = Schema; + +},{"./common":2,"./exception":4,"./type":13}],8:[function(require,module,exports){ +// Standard YAML's Core schema. +// http://www.yaml.org/spec/1.2/spec.html#id2804923 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, Core schema has no distinctions from JSON schema is JS-YAML. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./json') + ] +}); + +},{"../schema":7,"./json":12}],9:[function(require,module,exports){ +// JS-YAML's default schema for `load` function. +// It is not described in the YAML specification. +// +// This schema is based on JS-YAML's default safe schema and includes +// JavaScript-specific types: !!js/undefined, !!js/regexp and !!js/function. +// +// Also this schema is used as default base schema at `Schema.create` function. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = Schema.DEFAULT = new Schema({ + include: [ + require('./default_safe') + ], + explicit: [ + require('../type/js/undefined'), + require('../type/js/regexp'), + require('../type/js/function') + ] +}); + +},{"../schema":7,"../type/js/function":18,"../type/js/regexp":19,"../type/js/undefined":20,"./default_safe":10}],10:[function(require,module,exports){ +// JS-YAML's default schema for `safeLoad` function. +// It is not described in the YAML specification. +// +// This schema is based on standard YAML's Core schema and includes most of +// extra types described at YAML tag repository. (http://yaml.org/type/) + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./core') + ], + implicit: [ + require('../type/timestamp'), + require('../type/merge') + ], + explicit: [ + require('../type/binary'), + require('../type/omap'), + require('../type/pairs'), + require('../type/set') + ] +}); + +},{"../schema":7,"../type/binary":14,"../type/merge":22,"../type/omap":24,"../type/pairs":25,"../type/set":27,"../type/timestamp":29,"./core":8}],11:[function(require,module,exports){ +// Standard YAML's Failsafe schema. +// http://www.yaml.org/spec/1.2/spec.html#id2802346 + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + explicit: [ + require('../type/str'), + require('../type/seq'), + require('../type/map') + ] +}); + +},{"../schema":7,"../type/map":21,"../type/seq":26,"../type/str":28}],12:[function(require,module,exports){ +// Standard YAML's JSON schema. +// http://www.yaml.org/spec/1.2/spec.html#id2803231 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, this schema is not such strict as defined in the YAML specification. +// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./failsafe') + ], + implicit: [ + require('../type/null'), + require('../type/bool'), + require('../type/int'), + require('../type/float') + ] +}); + +},{"../schema":7,"../type/bool":15,"../type/float":16,"../type/int":17,"../type/null":23,"./failsafe":11}],13:[function(require,module,exports){ +'use strict'; + +var YAMLException = require('./exception'); + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +module.exports = Type; + +},{"./exception":4}],14:[function(require,module,exports){ +'use strict'; + +/*eslint-disable no-bitwise*/ + +var NodeBuffer; + +try { + // A trick for browserified version, to not include `Buffer` shim + var _require = require; + NodeBuffer = _require('buffer').Buffer; +} catch (__) {} + +var Type = require('../type'); + + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + +function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; +} + +function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + // Wrap into Buffer for NodeJS and leave Array for browser + if (NodeBuffer) return new NodeBuffer(result); + + return result; +} + +function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; +} + +function isBinary(object) { + return NodeBuffer && NodeBuffer.isBuffer(object); +} + +module.exports = new Type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}); + +},{"../type":13}],15:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); +} + +function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; +} + +function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; +} + +module.exports = new Type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' +}); + +},{"../type":13}],16:[function(require,module,exports){ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +var YAML_FLOAT_PATTERN = new RegExp( + '^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?' + + '|\\.[0-9_]+(?:[eE][-+][0-9]+)?' + + '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' + + '|[-+]?\\.(?:inf|Inf|INF)' + + '|\\.(?:nan|NaN|NAN))$'); + +function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data)) return false; + + return true; +} + +function constructYamlFloat(data) { + var value, sign, base, digits; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + digits = []; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + + } else if (value.indexOf(':') >= 0) { + value.split(':').forEach(function (v) { + digits.unshift(parseFloat(v, 10)); + }); + + value = 0.0; + base = 1; + + digits.forEach(function (d) { + value += d * base; + base *= 60; + }); + + return sign * value; + + } + return sign * parseFloat(value, 10); +} + + +var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; +} + +function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}); + +},{"../common":2,"../type":13}],17:[function(require,module,exports){ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); +} + +function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); +} + +function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); +} + +function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits; + } + + // base 8 + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits; + } + + // base 10 (except 0) or base 60 + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch === ':') break; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + if (!hasDigits) return false; + + // if !base60 - done; + if (ch !== ':') return true; + + // base60 almost not used, no needs to optimize + return /^(:[0-5]?[0-9])+$/.test(data.slice(index)); +} + +function constructYamlInteger(data) { + var value = data, sign = 1, ch, base, digits = []; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value, 16); + return sign * parseInt(value, 8); + } + + if (value.indexOf(':') !== -1) { + value.split(':').forEach(function (v) { + digits.unshift(parseInt(v, 10)); + }); + + value = 0; + base = 1; + + digits.forEach(function (d) { + value += (d * base); + base *= 60; + }); + + return sign * value; + + } + + return sign * parseInt(value, 10); +} + +function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (object) { return '0b' + object.toString(2); }, + octal: function (object) { return '0' + object.toString(8); }, + decimal: function (object) { return object.toString(10); }, + hexadecimal: function (object) { return '0x' + object.toString(16).toUpperCase(); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } +}); + +},{"../common":2,"../type":13}],18:[function(require,module,exports){ +'use strict'; + +var esprima; + +// Browserified version does not have esprima +// +// 1. For node.js just require module as deps +// 2. For browser try to require mudule via external AMD system. +// If not found - try to fallback to window.esprima. If not +// found too - then fail to parse. +// +try { + // workaround to exclude package from browserify list. + var _require = require; + esprima = _require('esprima'); +} catch (_) { + /*global window */ + if (typeof window !== 'undefined') esprima = window.esprima; +} + +var Type = require('../../type'); + +function resolveJavascriptFunction(data) { + if (data === null) return false; + + try { + var source = '(' + data + ')', + ast = esprima.parse(source, { range: true }); + + if (ast.type !== 'Program' || + ast.body.length !== 1 || + ast.body[0].type !== 'ExpressionStatement' || + ast.body[0].expression.type !== 'FunctionExpression') { + return false; + } + + return true; + } catch (err) { + return false; + } +} + +function constructJavascriptFunction(data) { + /*jslint evil:true*/ + + var source = '(' + data + ')', + ast = esprima.parse(source, { range: true }), + params = [], + body; + + if (ast.type !== 'Program' || + ast.body.length !== 1 || + ast.body[0].type !== 'ExpressionStatement' || + ast.body[0].expression.type !== 'FunctionExpression') { + throw new Error('Failed to resolve function'); + } + + ast.body[0].expression.params.forEach(function (param) { + params.push(param.name); + }); + + body = ast.body[0].expression.body.range; + + // Esprima's ranges include the first '{' and the last '}' characters on + // function expressions. So cut them out. + /*eslint-disable no-new-func*/ + return new Function(params, source.slice(body[0] + 1, body[1] - 1)); +} + +function representJavascriptFunction(object /*, style*/) { + return object.toString(); +} + +function isFunction(object) { + return Object.prototype.toString.call(object) === '[object Function]'; +} + +module.exports = new Type('tag:yaml.org,2002:js/function', { + kind: 'scalar', + resolve: resolveJavascriptFunction, + construct: constructJavascriptFunction, + predicate: isFunction, + represent: representJavascriptFunction +}); + +},{"../../type":13}],19:[function(require,module,exports){ +'use strict'; + +var Type = require('../../type'); + +function resolveJavascriptRegExp(data) { + if (data === null) return false; + if (data.length === 0) return false; + + var regexp = data, + tail = /\/([gim]*)$/.exec(data), + modifiers = ''; + + // if regexp starts with '/' it can have modifiers and must be properly closed + // `/foo/gim` - modifiers tail can be maximum 3 chars + if (regexp[0] === '/') { + if (tail) modifiers = tail[1]; + + if (modifiers.length > 3) return false; + // if expression starts with /, is should be properly terminated + if (regexp[regexp.length - modifiers.length - 1] !== '/') return false; + } + + return true; +} + +function constructJavascriptRegExp(data) { + var regexp = data, + tail = /\/([gim]*)$/.exec(data), + modifiers = ''; + + // `/foo/gim` - tail can be maximum 4 chars + if (regexp[0] === '/') { + if (tail) modifiers = tail[1]; + regexp = regexp.slice(1, regexp.length - modifiers.length - 1); + } + + return new RegExp(regexp, modifiers); +} + +function representJavascriptRegExp(object /*, style*/) { + var result = '/' + object.source + '/'; + + if (object.global) result += 'g'; + if (object.multiline) result += 'm'; + if (object.ignoreCase) result += 'i'; + + return result; +} + +function isRegExp(object) { + return Object.prototype.toString.call(object) === '[object RegExp]'; +} + +module.exports = new Type('tag:yaml.org,2002:js/regexp', { + kind: 'scalar', + resolve: resolveJavascriptRegExp, + construct: constructJavascriptRegExp, + predicate: isRegExp, + represent: representJavascriptRegExp +}); + +},{"../../type":13}],20:[function(require,module,exports){ +'use strict'; + +var Type = require('../../type'); + +function resolveJavascriptUndefined() { + return true; +} + +function constructJavascriptUndefined() { + /*eslint-disable no-undefined*/ + return undefined; +} + +function representJavascriptUndefined() { + return ''; +} + +function isUndefined(object) { + return typeof object === 'undefined'; +} + +module.exports = new Type('tag:yaml.org,2002:js/undefined', { + kind: 'scalar', + resolve: resolveJavascriptUndefined, + construct: constructJavascriptUndefined, + predicate: isUndefined, + represent: representJavascriptUndefined +}); + +},{"../../type":13}],21:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } +}); + +},{"../type":13}],22:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +function resolveYamlMerge(data) { + return data === '<<' || data === null; +} + +module.exports = new Type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}); + +},{"../type":13}],23:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); +} + +function constructYamlNull() { + return null; +} + +function isNull(object) { + return object === null; +} + +module.exports = new Type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; } + }, + defaultStyle: 'lowercase' +}); + +},{"../type":13}],24:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; +var _toString = Object.prototype.toString; + +function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; +} + +function constructYamlOmap(data) { + return data !== null ? data : []; +} + +module.exports = new Type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}); + +},{"../type":13}],25:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var _toString = Object.prototype.toString; + +function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; +} + +function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; +} + +module.exports = new Type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}); + +},{"../type":13}],26:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } +}); + +},{"../type":13}],27:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data) { + return data !== null ? data : {}; +} + +module.exports = new Type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}); + +},{"../type":13}],28:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } +}); + +},{"../type":13}],29:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + +var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} + +function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; +} + +function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); +} + +module.exports = new Type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}); + +},{"../type":13}],"/":[function(require,module,exports){ +'use strict'; + + +var yaml = require('./lib/js-yaml.js'); + + +module.exports = yaml; + +},{"./lib/js-yaml.js":1}]},{},[])("/") +});
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/js-yaml/dist/js-yaml.min.js b/node_modules/svgo/node_modules/js-yaml/dist/js-yaml.min.js new file mode 100644 index 00000000..211c64ce --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/dist/js-yaml.min.js @@ -0,0 +1,3 @@ +/* js-yaml 3.7.0 https://github.com/nodeca/js-yaml */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.jsyaml=e()}}(function(){return function e(t,n,i){function r(a,s){if(!n[a]){if(!t[a]){var c="function"==typeof require&&require;if(!s&&c)return c(a,!0);if(o)return o(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};t[a][0].call(l.exports,function(e){var n=t[a][1][e];return r(n?n:e)},l,l.exports,e,t,n,i)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;a<i.length;a++)r(i[a]);return r}({1:[function(e,t,n){"use strict";function i(e){return function(){throw new Error("Function "+e+" is deprecated and cannot be used.")}}var r=e("./js-yaml/loader"),o=e("./js-yaml/dumper");t.exports.Type=e("./js-yaml/type"),t.exports.Schema=e("./js-yaml/schema"),t.exports.FAILSAFE_SCHEMA=e("./js-yaml/schema/failsafe"),t.exports.JSON_SCHEMA=e("./js-yaml/schema/json"),t.exports.CORE_SCHEMA=e("./js-yaml/schema/core"),t.exports.DEFAULT_SAFE_SCHEMA=e("./js-yaml/schema/default_safe"),t.exports.DEFAULT_FULL_SCHEMA=e("./js-yaml/schema/default_full"),t.exports.load=r.load,t.exports.loadAll=r.loadAll,t.exports.safeLoad=r.safeLoad,t.exports.safeLoadAll=r.safeLoadAll,t.exports.dump=o.dump,t.exports.safeDump=o.safeDump,t.exports.YAMLException=e("./js-yaml/exception"),t.exports.MINIMAL_SCHEMA=e("./js-yaml/schema/failsafe"),t.exports.SAFE_SCHEMA=e("./js-yaml/schema/default_safe"),t.exports.DEFAULT_SCHEMA=e("./js-yaml/schema/default_full"),t.exports.scan=i("scan"),t.exports.parse=i("parse"),t.exports.compose=i("compose"),t.exports.addConstructor=i("addConstructor")},{"./js-yaml/dumper":3,"./js-yaml/exception":4,"./js-yaml/loader":5,"./js-yaml/schema":7,"./js-yaml/schema/core":8,"./js-yaml/schema/default_full":9,"./js-yaml/schema/default_safe":10,"./js-yaml/schema/failsafe":11,"./js-yaml/schema/json":12,"./js-yaml/type":13}],2:[function(e,t,n){"use strict";function i(e){return"undefined"==typeof e||null===e}function r(e){return"object"==typeof e&&null!==e}function o(e){return Array.isArray(e)?e:i(e)?[]:[e]}function a(e,t){var n,i,r,o;if(t)for(o=Object.keys(t),n=0,i=o.length;n<i;n+=1)r=o[n],e[r]=t[r];return e}function s(e,t){var n,i="";for(n=0;n<t;n+=1)i+=e;return i}function c(e){return 0===e&&Number.NEGATIVE_INFINITY===1/e}t.exports.isNothing=i,t.exports.isObject=r,t.exports.toArray=o,t.exports.repeat=s,t.exports.isNegativeZero=c,t.exports.extend=a},{}],3:[function(e,t,n){"use strict";function i(e,t){var n,i,r,o,a,s,c;if(null===t)return{};for(n={},i=Object.keys(t),r=0,o=i.length;r<o;r+=1)a=i[r],s=String(t[a]),"!!"===a.slice(0,2)&&(a="tag:yaml.org,2002:"+a.slice(2)),c=e.compiledTypeMap.fallback[a],c&&L.call(c.styleAliases,s)&&(s=c.styleAliases[s]),n[a]=s;return n}function r(e){var t,n,i;if(t=e.toString(16).toUpperCase(),e<=255)n="x",i=2;else if(e<=65535)n="u",i=4;else{if(!(e<=4294967295))throw new N("code point within a string may not be greater than 0xFFFFFFFF");n="U",i=8}return"\\"+n+F.repeat("0",i-t.length)+t}function o(e){this.schema=e.schema||M,this.indent=Math.max(1,e.indent||2),this.skipInvalid=e.skipInvalid||!1,this.flowLevel=F.isNothing(e.flowLevel)?-1:e.flowLevel,this.styleMap=i(this.schema,e.styles||null),this.sortKeys=e.sortKeys||!1,this.lineWidth=e.lineWidth||80,this.noRefs=e.noRefs||!1,this.noCompatMode=e.noCompatMode||!1,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result="",this.duplicates=[],this.usedDuplicates=null}function a(e,t){for(var n,i=F.repeat(" ",t),r=0,o=-1,a="",s=e.length;r<s;)o=e.indexOf("\n",r),o===-1?(n=e.slice(r),r=s):(n=e.slice(r,o+1),r=o+1),n.length&&"\n"!==n&&(a+=i),a+=n;return a}function s(e,t){return"\n"+F.repeat(" ",e.indent*t)}function c(e,t){var n,i,r;for(n=0,i=e.implicitTypes.length;n<i;n+=1)if(r=e.implicitTypes[n],r.resolve(t))return!0;return!1}function u(e){return e===q||e===D}function l(e){return 32<=e&&e<=126||161<=e&&e<=55295&&8232!==e&&8233!==e||57344<=e&&e<=65533&&65279!==e||65536<=e&&e<=1114111}function p(e){return l(e)&&65279!==e&&e!==H&&e!==Q&&e!==X&&e!==te&&e!==ie&&e!==V&&e!==P}function f(e){return l(e)&&65279!==e&&!u(e)&&e!==G&&e!==z&&e!==V&&e!==H&&e!==Q&&e!==X&&e!==te&&e!==ie&&e!==P&&e!==B&&e!==$&&e!==Y&&e!==ne&&e!==Z&&e!==K&&e!==R&&e!==W&&e!==J&&e!==ee}function d(e,t,n,i,r){var o,a,s=!1,c=!1,d=i!==-1,h=-1,m=f(e.charCodeAt(0))&&!u(e.charCodeAt(e.length-1));if(t)for(o=0;o<e.length;o++){if(a=e.charCodeAt(o),!l(a))return le;m=m&&p(a)}else{for(o=0;o<e.length;o++){if(a=e.charCodeAt(o),a===U)s=!0,d&&(c=c||o-h-1>i&&" "!==e[h+1],h=o);else if(!l(a))return le;m=m&&p(a)}c=c||d&&o-h-1>i&&" "!==e[h+1]}return s||c?" "===e[0]&&n>9?le:c?ue:ce:m&&!r(e)?ae:se}function h(e,t,n,i){e.dump=function(){function r(t){return c(e,t)}if(0===t.length)return"''";if(!e.noCompatMode&&oe.indexOf(t)!==-1)return"'"+t+"'";var o=e.indent*Math.max(1,n),s=e.lineWidth===-1?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o),u=i||e.flowLevel>-1&&n>=e.flowLevel;switch(d(t,u,e.indent,s,r)){case ae:return t;case se:return"'"+t.replace(/'/g,"''")+"'";case ce:return"|"+m(t,e.indent)+g(a(t,o));case ue:return">"+m(t,e.indent)+g(a(y(t,s),o));case le:return'"'+v(t,s)+'"';default:throw new N("impossible error: invalid scalar style")}}()}function m(e,t){var n=" "===e[0]?String(t):"",i="\n"===e[e.length-1],r=i&&("\n"===e[e.length-2]||"\n"===e),o=r?"+":i?"":"-";return n+o+"\n"}function g(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function y(e,t){for(var n,i,r=/(\n+)([^\n]*)/g,o=function(){var n=e.indexOf("\n");return n=n!==-1?n:e.length,r.lastIndex=n,x(e.slice(0,n),t)}(),a="\n"===e[0]||" "===e[0];i=r.exec(e);){var s=i[1],c=i[2];n=" "===c[0],o+=s+(a||n||""===c?"":"\n")+x(c,t),a=n}return o}function x(e,t){if(""===e||" "===e[0])return e;for(var n,i,r=/ [^ ]/g,o=0,a=0,s=0,c="";n=r.exec(e);)s=n.index,s-o>t&&(i=a>o?a:s,c+="\n"+e.slice(o,i),o=i+1),a=s;return c+="\n",c+=e.length-o>t&&a>o?e.slice(o,a)+"\n"+e.slice(a+1):e.slice(o),c.slice(1)}function v(e){for(var t,n,i="",o=0;o<e.length;o++)t=e.charCodeAt(o),n=re[t],i+=!n&&l(t)?e[o]:n||r(t);return i}function A(e,t,n){var i,r,o="",a=e.tag;for(i=0,r=n.length;i<r;i+=1)j(e,t,n[i],!1,!1)&&(0!==i&&(o+=", "),o+=e.dump);e.tag=a,e.dump="["+o+"]"}function b(e,t,n,i){var r,o,a="",c=e.tag;for(r=0,o=n.length;r<o;r+=1)j(e,t+1,n[r],!0,!0)&&(i&&0===r||(a+=s(e,t)),a+="- "+e.dump);e.tag=c,e.dump=a||"[]"}function w(e,t,n){var i,r,o,a,s,c="",u=e.tag,l=Object.keys(n);for(i=0,r=l.length;i<r;i+=1)s="",0!==i&&(s+=", "),o=l[i],a=n[o],j(e,t,o,!1,!1)&&(e.dump.length>1024&&(s+="? "),s+=e.dump+": ",j(e,t,a,!1,!1)&&(s+=e.dump,c+=s));e.tag=u,e.dump="{"+c+"}"}function C(e,t,n,i){var r,o,a,c,u,l,p="",f=e.tag,d=Object.keys(n);if(e.sortKeys===!0)d.sort();else if("function"==typeof e.sortKeys)d.sort(e.sortKeys);else if(e.sortKeys)throw new N("sortKeys must be a boolean or a function");for(r=0,o=d.length;r<o;r+=1)l="",i&&0===r||(l+=s(e,t)),a=d[r],c=n[a],j(e,t+1,a,!0,!0,!0)&&(u=null!==e.tag&&"?"!==e.tag||e.dump&&e.dump.length>1024,u&&(l+=e.dump&&U===e.dump.charCodeAt(0)?"?":"? "),l+=e.dump,u&&(l+=s(e,t)),j(e,t+1,c,!0,u)&&(l+=e.dump&&U===e.dump.charCodeAt(0)?":":": ",l+=e.dump,p+=l));e.tag=f,e.dump=p||"{}"}function k(e,t,n){var i,r,o,a,s,c;for(r=n?e.explicitTypes:e.implicitTypes,o=0,a=r.length;o<a;o+=1)if(s=r[o],(s.instanceOf||s.predicate)&&(!s.instanceOf||"object"==typeof t&&t instanceof s.instanceOf)&&(!s.predicate||s.predicate(t))){if(e.tag=n?s.tag:"?",s.represent){if(c=e.styleMap[s.tag]||s.defaultStyle,"[object Function]"===T.call(s.represent))i=s.represent(t,c);else{if(!L.call(s.represent,c))throw new N("!<"+s.tag+'> tag resolver accepts not "'+c+'" style');i=s.represent[c](t,c)}e.dump=i}return!0}return!1}function j(e,t,n,i,r,o){e.tag=null,e.dump=n,k(e,n,!1)||k(e,n,!0);var a=T.call(e.dump);i&&(i=e.flowLevel<0||e.flowLevel>t);var s,c,u="[object Object]"===a||"[object Array]"===a;if(u&&(s=e.duplicates.indexOf(n),c=s!==-1),(null!==e.tag&&"?"!==e.tag||c||2!==e.indent&&t>0)&&(r=!1),c&&e.usedDuplicates[s])e.dump="*ref_"+s;else{if(u&&c&&!e.usedDuplicates[s]&&(e.usedDuplicates[s]=!0),"[object Object]"===a)i&&0!==Object.keys(e.dump).length?(C(e,t,e.dump,r),c&&(e.dump="&ref_"+s+e.dump)):(w(e,t,e.dump),c&&(e.dump="&ref_"+s+" "+e.dump));else if("[object Array]"===a)i&&0!==e.dump.length?(b(e,t,e.dump,r),c&&(e.dump="&ref_"+s+e.dump)):(A(e,t,e.dump),c&&(e.dump="&ref_"+s+" "+e.dump));else{if("[object String]"!==a){if(e.skipInvalid)return!1;throw new N("unacceptable kind of an object to dump "+a)}"?"!==e.tag&&h(e,e.dump,t,o)}null!==e.tag&&"?"!==e.tag&&(e.dump="!<"+e.tag+"> "+e.dump)}return!0}function I(e,t){var n,i,r=[],o=[];for(S(e,r,o),n=0,i=o.length;n<i;n+=1)t.duplicates.push(r[o[n]]);t.usedDuplicates=new Array(i)}function S(e,t,n){var i,r,o;if(null!==e&&"object"==typeof e)if(r=t.indexOf(e),r!==-1)n.indexOf(r)===-1&&n.push(r);else if(t.push(e),Array.isArray(e))for(r=0,o=e.length;r<o;r+=1)S(e[r],t,n);else for(i=Object.keys(e),r=0,o=i.length;r<o;r+=1)S(e[i[r]],t,n)}function O(e,t){t=t||{};var n=new o(t);return n.noRefs||I(e,n),j(n,0,e,!0,!0)?n.dump+"\n":""}function E(e,t){return O(e,F.extend({schema:_},t))}var F=e("./common"),N=e("./exception"),M=e("./schema/default_full"),_=e("./schema/default_safe"),T=Object.prototype.toString,L=Object.prototype.hasOwnProperty,D=9,U=10,q=32,Y=33,R=34,P=35,W=37,B=38,K=39,$=42,H=44,G=45,V=58,Z=62,z=63,J=64,Q=91,X=93,ee=96,te=123,ne=124,ie=125,re={};re[0]="\\0",re[7]="\\a",re[8]="\\b",re[9]="\\t",re[10]="\\n",re[11]="\\v",re[12]="\\f",re[13]="\\r",re[27]="\\e",re[34]='\\"',re[92]="\\\\",re[133]="\\N",re[160]="\\_",re[8232]="\\L",re[8233]="\\P";var oe=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"],ae=1,se=2,ce=3,ue=4,le=5;t.exports.dump=O,t.exports.safeDump=E},{"./common":2,"./exception":4,"./schema/default_full":9,"./schema/default_safe":10}],4:[function(e,t,n){"use strict";function i(e,t){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||"",this.name="YAMLException",this.reason=e,this.mark=t,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():"")}i.prototype=Object.create(Error.prototype),i.prototype.constructor=i,i.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t},t.exports=i},{}],5:[function(e,t,n){"use strict";function i(e){return 10===e||13===e}function r(e){return 9===e||32===e}function o(e){return 9===e||32===e||10===e||13===e}function a(e){return 44===e||91===e||93===e||123===e||125===e}function s(e){var t;return 48<=e&&e<=57?e-48:(t=32|e,97<=t&&t<=102?t-97+10:-1)}function c(e){return 120===e?2:117===e?4:85===e?8:0}function u(e){return 48<=e&&e<=57?e-48:-1}function l(e){return 48===e?"\0":97===e?"":98===e?"\b":116===e?"\t":9===e?"\t":110===e?"\n":118===e?"\v":102===e?"\f":114===e?"\r":101===e?"":32===e?" ":34===e?'"':47===e?"/":92===e?"\\":78===e?"
":95===e?" ":76===e?"\u2028":80===e?"\u2029":""}function p(e){return e<=65535?String.fromCharCode(e):String.fromCharCode((e-65536>>10)+55296,(e-65536&1023)+56320)}function f(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||K,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function d(e,t){return new P(t,new W(e.filename,e.input,e.position,e.line,e.position-e.lineStart))}function h(e,t){throw d(e,t)}function m(e,t){e.onWarning&&e.onWarning.call(null,d(e,t))}function g(e,t,n,i){var r,o,a,s;if(t<n){if(s=e.input.slice(t,n),i)for(r=0,o=s.length;r<o;r+=1)a=s.charCodeAt(r),9===a||32<=a&&a<=1114111||h(e,"expected valid JSON character");else X.test(s)&&h(e,"the stream contains non-printable characters");e.result+=s}}function y(e,t,n,i){var r,o,a,s;for(R.isObject(n)||h(e,"cannot merge mappings; the provided source object is unacceptable"),r=Object.keys(n),a=0,s=r.length;a<s;a+=1)o=r[a],$.call(t,o)||(t[o]=n[o],i[o]=!0)}function x(e,t,n,i,r,o){var a,s;if(r=String(r),null===t&&(t={}),"tag:yaml.org,2002:merge"===i)if(Array.isArray(o))for(a=0,s=o.length;a<s;a+=1)y(e,t,o[a],n);else y(e,t,o,n);else e.json||$.call(n,r)||!$.call(t,r)||h(e,"duplicated mapping key"),t[r]=o,delete n[r];return t}function v(e){var t;t=e.input.charCodeAt(e.position),10===t?e.position++:13===t?(e.position++,10===e.input.charCodeAt(e.position)&&e.position++):h(e,"a line break is expected"),e.line+=1,e.lineStart=e.position}function A(e,t,n){for(var o=0,a=e.input.charCodeAt(e.position);0!==a;){for(;r(a);)a=e.input.charCodeAt(++e.position);if(t&&35===a)do a=e.input.charCodeAt(++e.position);while(10!==a&&13!==a&&0!==a);if(!i(a))break;for(v(e),a=e.input.charCodeAt(e.position),o++,e.lineIndent=0;32===a;)e.lineIndent++,a=e.input.charCodeAt(++e.position)}return n!==-1&&0!==o&&e.lineIndent<n&&m(e,"deficient indentation"),o}function b(e){var t,n=e.position;return t=e.input.charCodeAt(n),!(45!==t&&46!==t||t!==e.input.charCodeAt(n+1)||t!==e.input.charCodeAt(n+2)||(n+=3,t=e.input.charCodeAt(n),0!==t&&!o(t)))}function w(e,t){1===t?e.result+=" ":t>1&&(e.result+=R.repeat("\n",t-1))}function C(e,t,n){var s,c,u,l,p,f,d,h,m,y=e.kind,x=e.result;if(m=e.input.charCodeAt(e.position),o(m)||a(m)||35===m||38===m||42===m||33===m||124===m||62===m||39===m||34===m||37===m||64===m||96===m)return!1;if((63===m||45===m)&&(c=e.input.charCodeAt(e.position+1),o(c)||n&&a(c)))return!1;for(e.kind="scalar",e.result="",u=l=e.position,p=!1;0!==m;){if(58===m){if(c=e.input.charCodeAt(e.position+1),o(c)||n&&a(c))break}else if(35===m){if(s=e.input.charCodeAt(e.position-1),o(s))break}else{if(e.position===e.lineStart&&b(e)||n&&a(m))break;if(i(m)){if(f=e.line,d=e.lineStart,h=e.lineIndent,A(e,!1,-1),e.lineIndent>=t){p=!0,m=e.input.charCodeAt(e.position);continue}e.position=l,e.line=f,e.lineStart=d,e.lineIndent=h;break}}p&&(g(e,u,l,!1),w(e,e.line-f),u=l=e.position,p=!1),r(m)||(l=e.position+1),m=e.input.charCodeAt(++e.position)}return g(e,u,l,!1),!!e.result||(e.kind=y,e.result=x,!1)}function k(e,t){var n,r,o;if(n=e.input.charCodeAt(e.position),39!==n)return!1;for(e.kind="scalar",e.result="",e.position++,r=o=e.position;0!==(n=e.input.charCodeAt(e.position));)if(39===n){if(g(e,r,e.position,!0),n=e.input.charCodeAt(++e.position),39!==n)return!0;r=e.position,e.position++,o=e.position}else i(n)?(g(e,r,o,!0),w(e,A(e,!1,t)),r=o=e.position):e.position===e.lineStart&&b(e)?h(e,"unexpected end of the document within a single quoted scalar"):(e.position++,o=e.position);h(e,"unexpected end of the stream within a single quoted scalar")}function j(e,t){var n,r,o,a,u,l;if(l=e.input.charCodeAt(e.position),34!==l)return!1;for(e.kind="scalar",e.result="",e.position++,n=r=e.position;0!==(l=e.input.charCodeAt(e.position));){if(34===l)return g(e,n,e.position,!0),e.position++,!0;if(92===l){if(g(e,n,e.position,!0),l=e.input.charCodeAt(++e.position),i(l))A(e,!1,t);else if(l<256&&re[l])e.result+=oe[l],e.position++;else if((u=c(l))>0){for(o=u,a=0;o>0;o--)l=e.input.charCodeAt(++e.position),(u=s(l))>=0?a=(a<<4)+u:h(e,"expected hexadecimal character");e.result+=p(a),e.position++}else h(e,"unknown escape sequence");n=r=e.position}else i(l)?(g(e,n,r,!0),w(e,A(e,!1,t)),n=r=e.position):e.position===e.lineStart&&b(e)?h(e,"unexpected end of the document within a double quoted scalar"):(e.position++,r=e.position)}h(e,"unexpected end of the stream within a double quoted scalar")}function I(e,t){var n,i,r,a,s,c,u,l,p,f,d,m=!0,g=e.tag,y=e.anchor,v={};if(d=e.input.charCodeAt(e.position),91===d)a=93,u=!1,i=[];else{if(123!==d)return!1;a=125,u=!0,i={}}for(null!==e.anchor&&(e.anchorMap[e.anchor]=i),d=e.input.charCodeAt(++e.position);0!==d;){if(A(e,!0,t),d=e.input.charCodeAt(e.position),d===a)return e.position++,e.tag=g,e.anchor=y,e.kind=u?"mapping":"sequence",e.result=i,!0;m||h(e,"missed comma between flow collection entries"),p=l=f=null,s=c=!1,63===d&&(r=e.input.charCodeAt(e.position+1),o(r)&&(s=c=!0,e.position++,A(e,!0,t))),n=e.line,_(e,t,H,!1,!0),p=e.tag,l=e.result,A(e,!0,t),d=e.input.charCodeAt(e.position),!c&&e.line!==n||58!==d||(s=!0,d=e.input.charCodeAt(++e.position),A(e,!0,t),_(e,t,H,!1,!0),f=e.result),u?x(e,i,v,p,l,f):s?i.push(x(e,null,v,p,l,f)):i.push(l),A(e,!0,t),d=e.input.charCodeAt(e.position),44===d?(m=!0,d=e.input.charCodeAt(++e.position)):m=!1}h(e,"unexpected end of the stream within a flow collection")}function S(e,t){var n,o,a,s,c=z,l=!1,p=!1,f=t,d=0,m=!1;if(s=e.input.charCodeAt(e.position),124===s)o=!1;else{if(62!==s)return!1;o=!0}for(e.kind="scalar",e.result="";0!==s;)if(s=e.input.charCodeAt(++e.position),43===s||45===s)z===c?c=43===s?Q:J:h(e,"repeat of a chomping mode identifier");else{if(!((a=u(s))>=0))break;0===a?h(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):p?h(e,"repeat of an indentation width identifier"):(f=t+a-1,p=!0)}if(r(s)){do s=e.input.charCodeAt(++e.position);while(r(s));if(35===s)do s=e.input.charCodeAt(++e.position);while(!i(s)&&0!==s)}for(;0!==s;){for(v(e),e.lineIndent=0,s=e.input.charCodeAt(e.position);(!p||e.lineIndent<f)&&32===s;)e.lineIndent++,s=e.input.charCodeAt(++e.position);if(!p&&e.lineIndent>f&&(f=e.lineIndent),i(s))d++;else{if(e.lineIndent<f){c===Q?e.result+=R.repeat("\n",l?1+d:d):c===z&&l&&(e.result+="\n");break}for(o?r(s)?(m=!0,e.result+=R.repeat("\n",l?1+d:d)):m?(m=!1,e.result+=R.repeat("\n",d+1)):0===d?l&&(e.result+=" "):e.result+=R.repeat("\n",d):e.result+=R.repeat("\n",l?1+d:d),l=!0,p=!0,d=0,n=e.position;!i(s)&&0!==s;)s=e.input.charCodeAt(++e.position);g(e,n,e.position,!1)}}return!0}function O(e,t){var n,i,r,a=e.tag,s=e.anchor,c=[],u=!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=c),r=e.input.charCodeAt(e.position);0!==r&&45===r&&(i=e.input.charCodeAt(e.position+1),o(i));)if(u=!0,e.position++,A(e,!0,-1)&&e.lineIndent<=t)c.push(null),r=e.input.charCodeAt(e.position);else if(n=e.line,_(e,t,V,!1,!0),c.push(e.result),A(e,!0,-1),r=e.input.charCodeAt(e.position),(e.line===n||e.lineIndent>t)&&0!==r)h(e,"bad indentation of a sequence entry");else if(e.lineIndent<t)break;return!!u&&(e.tag=a,e.anchor=s,e.kind="sequence",e.result=c,!0)}function E(e,t,n){var i,a,s,c,u=e.tag,l=e.anchor,p={},f={},d=null,m=null,g=null,y=!1,v=!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=p),c=e.input.charCodeAt(e.position);0!==c;){if(i=e.input.charCodeAt(e.position+1),s=e.line,63!==c&&58!==c||!o(i)){if(!_(e,n,G,!1,!0))break;if(e.line===s){for(c=e.input.charCodeAt(e.position);r(c);)c=e.input.charCodeAt(++e.position);if(58===c)c=e.input.charCodeAt(++e.position),o(c)||h(e,"a whitespace character is expected after the key-value separator within a block mapping"),y&&(x(e,p,f,d,m,null),d=m=g=null),v=!0,y=!1,a=!1,d=e.tag,m=e.result;else{if(!v)return e.tag=u,e.anchor=l,!0;h(e,"can not read an implicit mapping pair; a colon is missed")}}else{if(!v)return e.tag=u,e.anchor=l,!0;h(e,"can not read a block mapping entry; a multiline key may not be an implicit key")}}else 63===c?(y&&(x(e,p,f,d,m,null),d=m=g=null),v=!0,y=!0,a=!0):y?(y=!1,a=!0):h(e,"incomplete explicit mapping pair; a key node is missed"),e.position+=1,c=i;if((e.line===s||e.lineIndent>t)&&(_(e,t,Z,!0,a)&&(y?m=e.result:g=e.result),y||(x(e,p,f,d,m,g),d=m=g=null),A(e,!0,-1),c=e.input.charCodeAt(e.position)),e.lineIndent>t&&0!==c)h(e,"bad indentation of a mapping entry");else if(e.lineIndent<t)break}return y&&x(e,p,f,d,m,null),v&&(e.tag=u,e.anchor=l,e.kind="mapping",e.result=p),v}function F(e){var t,n,i,r,a=!1,s=!1;if(r=e.input.charCodeAt(e.position),33!==r)return!1;if(null!==e.tag&&h(e,"duplication of a tag property"),r=e.input.charCodeAt(++e.position),60===r?(a=!0,r=e.input.charCodeAt(++e.position)):33===r?(s=!0,n="!!",r=e.input.charCodeAt(++e.position)):n="!",t=e.position,a){do r=e.input.charCodeAt(++e.position);while(0!==r&&62!==r);e.position<e.length?(i=e.input.slice(t,e.position),r=e.input.charCodeAt(++e.position)):h(e,"unexpected end of the stream within a verbatim tag")}else{for(;0!==r&&!o(r);)33===r&&(s?h(e,"tag suffix cannot contain exclamation marks"):(n=e.input.slice(t-1,e.position+1),ne.test(n)||h(e,"named tag handle cannot contain such characters"),s=!0,t=e.position+1)),r=e.input.charCodeAt(++e.position);i=e.input.slice(t,e.position),te.test(i)&&h(e,"tag suffix cannot contain flow indicator characters")}return i&&!ie.test(i)&&h(e,"tag name cannot contain such characters: "+i),a?e.tag=i:$.call(e.tagMap,n)?e.tag=e.tagMap[n]+i:"!"===n?e.tag="!"+i:"!!"===n?e.tag="tag:yaml.org,2002:"+i:h(e,'undeclared tag handle "'+n+'"'),!0}function N(e){var t,n;if(n=e.input.charCodeAt(e.position),38!==n)return!1;for(null!==e.anchor&&h(e,"duplication of an anchor property"),n=e.input.charCodeAt(++e.position),t=e.position;0!==n&&!o(n)&&!a(n);)n=e.input.charCodeAt(++e.position);return e.position===t&&h(e,"name of an anchor node must contain at least one character"),e.anchor=e.input.slice(t,e.position),!0}function M(e){var t,n,i;if(i=e.input.charCodeAt(e.position),42!==i)return!1;for(i=e.input.charCodeAt(++e.position),t=e.position;0!==i&&!o(i)&&!a(i);)i=e.input.charCodeAt(++e.position);return e.position===t&&h(e,"name of an alias node must contain at least one character"),n=e.input.slice(t,e.position),e.anchorMap.hasOwnProperty(n)||h(e,'unidentified alias "'+n+'"'),e.result=e.anchorMap[n],A(e,!0,-1),!0}function _(e,t,n,i,r){var o,a,s,c,u,l,p,f,d=1,m=!1,g=!1;if(null!==e.listener&&e.listener("open",e),e.tag=null,e.anchor=null,e.kind=null,e.result=null,o=a=s=Z===n||V===n,i&&A(e,!0,-1)&&(m=!0,e.lineIndent>t?d=1:e.lineIndent===t?d=0:e.lineIndent<t&&(d=-1)),1===d)for(;F(e)||N(e);)A(e,!0,-1)?(m=!0,s=o,e.lineIndent>t?d=1:e.lineIndent===t?d=0:e.lineIndent<t&&(d=-1)):s=!1;if(s&&(s=m||r),1!==d&&Z!==n||(p=H===n||G===n?t:t+1,f=e.position-e.lineStart,1===d?s&&(O(e,f)||E(e,f,p))||I(e,p)?g=!0:(a&&S(e,p)||k(e,p)||j(e,p)?g=!0:M(e)?(g=!0,null===e.tag&&null===e.anchor||h(e,"alias node should not have any properties")):C(e,p,H===n)&&(g=!0,null===e.tag&&(e.tag="?")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===d&&(g=s&&O(e,f))),null!==e.tag&&"!"!==e.tag)if("?"===e.tag){for(c=0,u=e.implicitTypes.length;c<u;c+=1)if(l=e.implicitTypes[c],l.resolve(e.result)){e.result=l.construct(e.result),e.tag=l.tag,null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);break}}else $.call(e.typeMap[e.kind||"fallback"],e.tag)?(l=e.typeMap[e.kind||"fallback"][e.tag],null!==e.result&&l.kind!==e.kind&&h(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+l.kind+'", not "'+e.kind+'"'),l.resolve(e.result)?(e.result=l.construct(e.result),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):h(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")):h(e,"unknown tag !<"+e.tag+">");return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||g}function T(e){var t,n,a,s,c=e.position,u=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap={},e.anchorMap={};0!==(s=e.input.charCodeAt(e.position))&&(A(e,!0,-1),s=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==s));){for(u=!0,s=e.input.charCodeAt(++e.position),t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);for(n=e.input.slice(t,e.position),a=[],n.length<1&&h(e,"directive name must not be less than one character in length");0!==s;){for(;r(s);)s=e.input.charCodeAt(++e.position);if(35===s){do s=e.input.charCodeAt(++e.position);while(0!==s&&!i(s));break}if(i(s))break;for(t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);a.push(e.input.slice(t,e.position))}0!==s&&v(e),$.call(se,n)?se[n](e,n,a):m(e,'unknown document directive "'+n+'"')}return A(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,A(e,!0,-1)):u&&h(e,"directives end mark is expected"),_(e,e.lineIndent-1,Z,!1,!0),A(e,!0,-1),e.checkLineBreaks&&ee.test(e.input.slice(c,e.position))&&m(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&b(e)?void(46===e.input.charCodeAt(e.position)&&(e.position+=3,A(e,!0,-1))):void(e.position<e.length-1&&h(e,"end of the stream or a document separator is expected"))}function L(e,t){e=String(e),t=t||{},0!==e.length&&(10!==e.charCodeAt(e.length-1)&&13!==e.charCodeAt(e.length-1)&&(e+="\n"),65279===e.charCodeAt(0)&&(e=e.slice(1)));var n=new f(e,t);for(n.input+="\0";32===n.input.charCodeAt(n.position);)n.lineIndent+=1,n.position+=1;for(;n.position<n.length-1;)T(n);return n.documents}function D(e,t,n){var i,r,o=L(e,n);for(i=0,r=o.length;i<r;i+=1)t(o[i])}function U(e,t){var n=L(e,t);if(0!==n.length){if(1===n.length)return n[0];throw new P("expected a single document in the stream, but found more")}}function q(e,t,n){D(e,t,R.extend({schema:B},n))}function Y(e,t){return U(e,R.extend({schema:B},t))}for(var R=e("./common"),P=e("./exception"),W=e("./mark"),B=e("./schema/default_safe"),K=e("./schema/default_full"),$=Object.prototype.hasOwnProperty,H=1,G=2,V=3,Z=4,z=1,J=2,Q=3,X=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,ee=/[\x85\u2028\u2029]/,te=/[,\[\]\{\}]/,ne=/^(?:!|!!|![a-z\-]+!)$/i,ie=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i,re=new Array(256),oe=new Array(256),ae=0;ae<256;ae++)re[ae]=l(ae)?1:0,oe[ae]=l(ae);var se={YAML:function(e,t,n){var i,r,o;null!==e.version&&h(e,"duplication of %YAML directive"),1!==n.length&&h(e,"YAML directive accepts exactly one argument"),i=/^([0-9]+)\.([0-9]+)$/.exec(n[0]),null===i&&h(e,"ill-formed argument of the YAML directive"),r=parseInt(i[1],10),o=parseInt(i[2],10),1!==r&&h(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=o<2,1!==o&&2!==o&&m(e,"unsupported YAML version of the document")},TAG:function(e,t,n){var i,r;2!==n.length&&h(e,"TAG directive accepts exactly two arguments"),i=n[0],r=n[1],ne.test(i)||h(e,"ill-formed tag handle (first argument) of the TAG directive"),$.call(e.tagMap,i)&&h(e,'there is a previously declared suffix for "'+i+'" tag handle'),ie.test(r)||h(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[i]=r}};t.exports.loadAll=D,t.exports.load=U,t.exports.safeLoadAll=q,t.exports.safeLoad=Y},{"./common":2,"./exception":4,"./mark":6,"./schema/default_full":9,"./schema/default_safe":10}],6:[function(e,t,n){"use strict";function i(e,t,n,i,r){this.name=e,this.buffer=t,this.position=n,this.line=i,this.column=r}var r=e("./common");i.prototype.getSnippet=function(e,t){var n,i,o,a,s;if(!this.buffer)return null;for(e=e||4,t=t||75,n="",i=this.position;i>0&&"\0\r\n
\u2028\u2029".indexOf(this.buffer.charAt(i-1))===-1;)if(i-=1,this.position-i>t/2-1){n=" ... ",i+=5;break}for(o="",a=this.position;a<this.buffer.length&&"\0\r\n
\u2028\u2029".indexOf(this.buffer.charAt(a))===-1;)if(a+=1,a-this.position>t/2-1){o=" ... ",a-=5;break}return s=this.buffer.slice(i,a),r.repeat(" ",e)+n+s+o+"\n"+r.repeat(" ",e+this.position-i+n.length)+"^"},i.prototype.toString=function(e){var t,n="";return this.name&&(n+='in "'+this.name+'" '),n+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet(),t&&(n+=":\n"+t)),n},t.exports=i},{"./common":2}],7:[function(e,t,n){"use strict";function i(e,t,n){var r=[];return e.include.forEach(function(e){n=i(e,t,n)}),e[t].forEach(function(e){n.forEach(function(t,n){t.tag===e.tag&&t.kind===e.kind&&r.push(n)}),n.push(e)}),n.filter(function(e,t){return r.indexOf(t)===-1})}function r(){function e(e){i[e.kind][e.tag]=i.fallback[e.tag]=e}var t,n,i={scalar:{},sequence:{},mapping:{},fallback:{}};for(t=0,n=arguments.length;t<n;t+=1)arguments[t].forEach(e);return i}function o(e){this.include=e.include||[],this.implicit=e.implicit||[],this.explicit=e.explicit||[],this.implicit.forEach(function(e){if(e.loadKind&&"scalar"!==e.loadKind)throw new s("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.")}),this.compiledImplicit=i(this,"implicit",[]),this.compiledExplicit=i(this,"explicit",[]),this.compiledTypeMap=r(this.compiledImplicit,this.compiledExplicit)}var a=e("./common"),s=e("./exception"),c=e("./type");o.DEFAULT=null,o.create=function(){var e,t;switch(arguments.length){case 1:e=o.DEFAULT,t=arguments[0];break;case 2:e=arguments[0],t=arguments[1];break;default:throw new s("Wrong number of arguments for Schema.create function")}if(e=a.toArray(e),t=a.toArray(t),!e.every(function(e){return e instanceof o}))throw new s("Specified list of super schemas (or a single Schema object) contains a non-Schema object.");if(!t.every(function(e){return e instanceof c}))throw new s("Specified list of YAML types (or a single Type object) contains a non-Type object.");return new o({include:e,explicit:t})},t.exports=o},{"./common":2,"./exception":4,"./type":13}],8:[function(e,t,n){"use strict";var i=e("../schema");t.exports=new i({include:[e("./json")]})},{"../schema":7,"./json":12}],9:[function(e,t,n){"use strict";var i=e("../schema");t.exports=i.DEFAULT=new i({include:[e("./default_safe")],explicit:[e("../type/js/undefined"),e("../type/js/regexp"),e("../type/js/function")]})},{"../schema":7,"../type/js/function":18,"../type/js/regexp":19,"../type/js/undefined":20,"./default_safe":10}],10:[function(e,t,n){"use strict";var i=e("../schema");t.exports=new i({include:[e("./core")],implicit:[e("../type/timestamp"),e("../type/merge")],explicit:[e("../type/binary"),e("../type/omap"),e("../type/pairs"),e("../type/set")]})},{"../schema":7,"../type/binary":14,"../type/merge":22,"../type/omap":24,"../type/pairs":25,"../type/set":27,"../type/timestamp":29,"./core":8}],11:[function(e,t,n){"use strict";var i=e("../schema");t.exports=new i({explicit:[e("../type/str"),e("../type/seq"),e("../type/map")]})},{"../schema":7,"../type/map":21,"../type/seq":26,"../type/str":28}],12:[function(e,t,n){"use strict";var i=e("../schema");t.exports=new i({include:[e("./failsafe")],implicit:[e("../type/null"),e("../type/bool"),e("../type/int"),e("../type/float")]})},{"../schema":7,"../type/bool":15,"../type/float":16,"../type/int":17,"../type/null":23,"./failsafe":11}],13:[function(e,t,n){"use strict";function i(e){var t={};return null!==e&&Object.keys(e).forEach(function(n){e[n].forEach(function(e){t[String(e)]=n})}),t}function r(e,t){if(t=t||{},Object.keys(t).forEach(function(t){if(a.indexOf(t)===-1)throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')}),this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.defaultStyle=t.defaultStyle||null,this.styleAliases=i(t.styleAliases||null),s.indexOf(this.kind)===-1)throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}var o=e("./exception"),a=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],s=["scalar","sequence","mapping"];t.exports=r},{"./exception":4}],14:[function(e,t,n){"use strict";function i(e){if(null===e)return!1;var t,n,i=0,r=e.length,o=l;for(n=0;n<r;n++)if(t=o.indexOf(e.charAt(n)),!(t>64)){if(t<0)return!1;i+=6}return i%8===0}function r(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=l,a=0,c=[];for(t=0;t<r;t++)t%4===0&&t&&(c.push(a>>16&255),c.push(a>>8&255),c.push(255&a)),a=a<<6|o.indexOf(i.charAt(t));return n=r%4*6,0===n?(c.push(a>>16&255),c.push(a>>8&255),c.push(255&a)):18===n?(c.push(a>>10&255),c.push(a>>2&255)):12===n&&c.push(a>>4&255),s?new s(c):c}function o(e){var t,n,i="",r=0,o=e.length,a=l;for(t=0;t<o;t++)t%3===0&&t&&(i+=a[r>>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]),r=(r<<8)+e[t];return n=o%3,0===n?(i+=a[r>>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]):2===n?(i+=a[r>>10&63],i+=a[r>>4&63], +i+=a[r<<2&63],i+=a[64]):1===n&&(i+=a[r>>2&63],i+=a[r<<4&63],i+=a[64],i+=a[64]),i}function a(e){return s&&s.isBuffer(e)}var s;try{var c=e;s=c("buffer").Buffer}catch(e){}var u=e("../type"),l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";t.exports=new u("tag:yaml.org,2002:binary",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../type":13}],15:[function(e,t,n){"use strict";function i(e){if(null===e)return!1;var t=e.length;return 4===t&&("true"===e||"True"===e||"TRUE"===e)||5===t&&("false"===e||"False"===e||"FALSE"===e)}function r(e){return"true"===e||"True"===e||"TRUE"===e}function o(e){return"[object Boolean]"===Object.prototype.toString.call(e)}var a=e("../type");t.exports=new a("tag:yaml.org,2002:bool",{kind:"scalar",resolve:i,construct:r,predicate:o,represent:{lowercase:function(e){return e?"true":"false"},uppercase:function(e){return e?"TRUE":"FALSE"},camelcase:function(e){return e?"True":"False"}},defaultStyle:"lowercase"})},{"../type":13}],16:[function(e,t,n){"use strict";function i(e){return null!==e&&!!u.test(e)}function r(e){var t,n,i,r;return t=e.replace(/_/g,"").toLowerCase(),n="-"===t[0]?-1:1,r=[],"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:t.indexOf(":")>=0?(t.split(":").forEach(function(e){r.unshift(parseFloat(e,10))}),t=0,i=1,r.forEach(function(e){t+=e*i,i*=60}),n*t):n*parseFloat(t,10)}function o(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(s.isNegativeZero(e))return"-0.0";return n=e.toString(10),l.test(n)?n.replace("e",".e"):n}function a(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!==0||s.isNegativeZero(e))}var s=e("../common"),c=e("../type"),u=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?|\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),l=/^[-+]?[0-9]+e/;t.exports=new c("tag:yaml.org,2002:float",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o,defaultStyle:"lowercase"})},{"../common":2,"../type":13}],17:[function(e,t,n){"use strict";function i(e){return 48<=e&&e<=57||65<=e&&e<=70||97<=e&&e<=102}function r(e){return 48<=e&&e<=55}function o(e){return 48<=e&&e<=57}function a(e){if(null===e)return!1;var t,n=e.length,a=0,s=!1;if(!n)return!1;if(t=e[a],"-"!==t&&"+"!==t||(t=e[++a]),"0"===t){if(a+1===n)return!0;if(t=e[++a],"b"===t){for(a++;a<n;a++)if(t=e[a],"_"!==t){if("0"!==t&&"1"!==t)return!1;s=!0}return s}if("x"===t){for(a++;a<n;a++)if(t=e[a],"_"!==t){if(!i(e.charCodeAt(a)))return!1;s=!0}return s}for(;a<n;a++)if(t=e[a],"_"!==t){if(!r(e.charCodeAt(a)))return!1;s=!0}return s}for(;a<n;a++)if(t=e[a],"_"!==t){if(":"===t)break;if(!o(e.charCodeAt(a)))return!1;s=!0}return!!s&&(":"!==t||/^(:[0-5]?[0-9])+$/.test(e.slice(a)))}function s(e){var t,n,i=e,r=1,o=[];return i.indexOf("_")!==-1&&(i=i.replace(/_/g,"")),t=i[0],"-"!==t&&"+"!==t||("-"===t&&(r=-1),i=i.slice(1),t=i[0]),"0"===i?0:"0"===t?"b"===i[1]?r*parseInt(i.slice(2),2):"x"===i[1]?r*parseInt(i,16):r*parseInt(i,8):i.indexOf(":")!==-1?(i.split(":").forEach(function(e){o.unshift(parseInt(e,10))}),i=0,n=1,o.forEach(function(e){i+=e*n,n*=60}),r*i):r*parseInt(i,10)}function c(e){return"[object Number]"===Object.prototype.toString.call(e)&&e%1===0&&!u.isNegativeZero(e)}var u=e("../common"),l=e("../type");t.exports=new l("tag:yaml.org,2002:int",{kind:"scalar",resolve:a,construct:s,predicate:c,represent:{binary:function(e){return"0b"+e.toString(2)},octal:function(e){return"0"+e.toString(8)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return"0x"+e.toString(16).toUpperCase()}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})},{"../common":2,"../type":13}],18:[function(e,t,n){"use strict";function i(e){if(null===e)return!1;try{var t="("+e+")",n=s.parse(t,{range:!0});return"Program"===n.type&&1===n.body.length&&"ExpressionStatement"===n.body[0].type&&"FunctionExpression"===n.body[0].expression.type}catch(e){return!1}}function r(e){var t,n="("+e+")",i=s.parse(n,{range:!0}),r=[];if("Program"!==i.type||1!==i.body.length||"ExpressionStatement"!==i.body[0].type||"FunctionExpression"!==i.body[0].expression.type)throw new Error("Failed to resolve function");return i.body[0].expression.params.forEach(function(e){r.push(e.name)}),t=i.body[0].expression.body.range,new Function(r,n.slice(t[0]+1,t[1]-1))}function o(e){return e.toString()}function a(e){return"[object Function]"===Object.prototype.toString.call(e)}var s;try{var c=e;s=c("esprima")}catch(e){"undefined"!=typeof window&&(s=window.esprima)}var u=e("../../type");t.exports=new u("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],19:[function(e,t,n){"use strict";function i(e){if(null===e)return!1;if(0===e.length)return!1;var t=e,n=/\/([gim]*)$/.exec(e),i="";if("/"===t[0]){if(n&&(i=n[1]),i.length>3)return!1;if("/"!==t[t.length-i.length-1])return!1}return!0}function r(e){var t=e,n=/\/([gim]*)$/.exec(e),i="";return"/"===t[0]&&(n&&(i=n[1]),t=t.slice(1,t.length-i.length-1)),new RegExp(t,i)}function o(e){var t="/"+e.source+"/";return e.global&&(t+="g"),e.multiline&&(t+="m"),e.ignoreCase&&(t+="i"),t}function a(e){return"[object RegExp]"===Object.prototype.toString.call(e)}var s=e("../../type");t.exports=new s("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],20:[function(e,t,n){"use strict";function i(){return!0}function r(){}function o(){return""}function a(e){return"undefined"==typeof e}var s=e("../../type");t.exports=new s("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],21:[function(e,t,n){"use strict";var i=e("../type");t.exports=new i("tag:yaml.org,2002:map",{kind:"mapping",construct:function(e){return null!==e?e:{}}})},{"../type":13}],22:[function(e,t,n){"use strict";function i(e){return"<<"===e||null===e}var r=e("../type");t.exports=new r("tag:yaml.org,2002:merge",{kind:"scalar",resolve:i})},{"../type":13}],23:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t=e.length;return 1===t&&"~"===e||4===t&&("null"===e||"Null"===e||"NULL"===e)}function r(){return null}function o(e){return null===e}var a=e("../type");t.exports=new a("tag:yaml.org,2002:null",{kind:"scalar",resolve:i,construct:r,predicate:o,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})},{"../type":13}],24:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t,n,i,r,o,c=[],u=e;for(t=0,n=u.length;t<n;t+=1){if(i=u[t],o=!1,"[object Object]"!==s.call(i))return!1;for(r in i)if(a.call(i,r)){if(o)return!1;o=!0}if(!o)return!1;if(c.indexOf(r)!==-1)return!1;c.push(r)}return!0}function r(e){return null!==e?e:[]}var o=e("../type"),a=Object.prototype.hasOwnProperty,s=Object.prototype.toString;t.exports=new o("tag:yaml.org,2002:omap",{kind:"sequence",resolve:i,construct:r})},{"../type":13}],25:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t,n,i,r,o,s=e;for(o=new Array(s.length),t=0,n=s.length;t<n;t+=1){if(i=s[t],"[object Object]"!==a.call(i))return!1;if(r=Object.keys(i),1!==r.length)return!1;o[t]=[r[0],i[r[0]]]}return!0}function r(e){if(null===e)return[];var t,n,i,r,o,a=e;for(o=new Array(a.length),t=0,n=a.length;t<n;t+=1)i=a[t],r=Object.keys(i),o[t]=[r[0],i[r[0]]];return o}var o=e("../type"),a=Object.prototype.toString;t.exports=new o("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:i,construct:r})},{"../type":13}],26:[function(e,t,n){"use strict";var i=e("../type");t.exports=new i("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(e){return null!==e?e:[]}})},{"../type":13}],27:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t,n=e;for(t in n)if(a.call(n,t)&&null!==n[t])return!1;return!0}function r(e){return null!==e?e:{}}var o=e("../type"),a=Object.prototype.hasOwnProperty;t.exports=new o("tag:yaml.org,2002:set",{kind:"mapping",resolve:i,construct:r})},{"../type":13}],28:[function(e,t,n){"use strict";var i=e("../type");t.exports=new i("tag:yaml.org,2002:str",{kind:"scalar",construct:function(e){return null!==e?e:""}})},{"../type":13}],29:[function(e,t,n){"use strict";function i(e){return null!==e&&(null!==s.exec(e)||null!==c.exec(e))}function r(e){var t,n,i,r,o,a,u,l,p,f,d=0,h=null;if(t=s.exec(e),null===t&&(t=c.exec(e)),null===t)throw new Error("Date resolve error");if(n=+t[1],i=+t[2]-1,r=+t[3],!t[4])return new Date(Date.UTC(n,i,r));if(o=+t[4],a=+t[5],u=+t[6],t[7]){for(d=t[7].slice(0,3);d.length<3;)d+="0";d=+d}return t[9]&&(l=+t[10],p=+(t[11]||0),h=6e4*(60*l+p),"-"===t[9]&&(h=-h)),f=new Date(Date.UTC(n,i,r,o,a,u,d)),h&&f.setTime(f.getTime()-h),f}function o(e){return e.toISOString()}var a=e("../type"),s=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),c=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");t.exports=new a("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:i,construct:r,instanceOf:Date,represent:o})},{"../type":13}],"/":[function(e,t,n){"use strict";var i=e("./lib/js-yaml.js");t.exports=i},{"./lib/js-yaml.js":1}]},{},[])("/")}); diff --git a/node_modules/svgo/node_modules/js-yaml/index.js b/node_modules/svgo/node_modules/js-yaml/index.js new file mode 100644 index 00000000..13744352 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/index.js @@ -0,0 +1,7 @@ +'use strict'; + + +var yaml = require('./lib/js-yaml.js'); + + +module.exports = yaml; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml.js new file mode 100644 index 00000000..f0e92818 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml.js @@ -0,0 +1,39 @@ +'use strict'; + + +var loader = require('./js-yaml/loader'); +var dumper = require('./js-yaml/dumper'); + + +function deprecated(name) { + return function () { + throw new Error('Function ' + name + ' is deprecated and cannot be used.'); + }; +} + + +module.exports.Type = require('./js-yaml/type'); +module.exports.Schema = require('./js-yaml/schema'); +module.exports.FAILSAFE_SCHEMA = require('./js-yaml/schema/failsafe'); +module.exports.JSON_SCHEMA = require('./js-yaml/schema/json'); +module.exports.CORE_SCHEMA = require('./js-yaml/schema/core'); +module.exports.DEFAULT_SAFE_SCHEMA = require('./js-yaml/schema/default_safe'); +module.exports.DEFAULT_FULL_SCHEMA = require('./js-yaml/schema/default_full'); +module.exports.load = loader.load; +module.exports.loadAll = loader.loadAll; +module.exports.safeLoad = loader.safeLoad; +module.exports.safeLoadAll = loader.safeLoadAll; +module.exports.dump = dumper.dump; +module.exports.safeDump = dumper.safeDump; +module.exports.YAMLException = require('./js-yaml/exception'); + +// Deprecated schema names from JS-YAML 2.0.x +module.exports.MINIMAL_SCHEMA = require('./js-yaml/schema/failsafe'); +module.exports.SAFE_SCHEMA = require('./js-yaml/schema/default_safe'); +module.exports.DEFAULT_SCHEMA = require('./js-yaml/schema/default_full'); + +// Deprecated functions from JS-YAML 1.x.x +module.exports.scan = deprecated('scan'); +module.exports.parse = deprecated('parse'); +module.exports.compose = deprecated('compose'); +module.exports.addConstructor = deprecated('addConstructor'); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/common.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/common.js new file mode 100644 index 00000000..25ef7d8e --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/common.js @@ -0,0 +1,59 @@ +'use strict'; + + +function isNothing(subject) { + return (typeof subject === 'undefined') || (subject === null); +} + + +function isObject(subject) { + return (typeof subject === 'object') && (subject !== null); +} + + +function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + + return [ sequence ]; +} + + +function extend(target, source) { + var index, length, key, sourceKeys; + + if (source) { + sourceKeys = Object.keys(source); + + for (index = 0, length = sourceKeys.length; index < length; index += 1) { + key = sourceKeys[index]; + target[key] = source[key]; + } + } + + return target; +} + + +function repeat(string, count) { + var result = '', cycle; + + for (cycle = 0; cycle < count; cycle += 1) { + result += string; + } + + return result; +} + + +function isNegativeZero(number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); +} + + +module.exports.isNothing = isNothing; +module.exports.isObject = isObject; +module.exports.toArray = toArray; +module.exports.repeat = repeat; +module.exports.isNegativeZero = isNegativeZero; +module.exports.extend = extend; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/dumper.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/dumper.js new file mode 100644 index 00000000..203f436b --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/dumper.js @@ -0,0 +1,801 @@ +'use strict'; + +/*eslint-disable no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var DEFAULT_FULL_SCHEMA = require('./schema/default_full'); +var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe'); + +var _toString = Object.prototype.toString; +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +var CHAR_TAB = 0x09; /* Tab */ +var CHAR_LINE_FEED = 0x0A; /* LF */ +var CHAR_SPACE = 0x20; /* Space */ +var CHAR_EXCLAMATION = 0x21; /* ! */ +var CHAR_DOUBLE_QUOTE = 0x22; /* " */ +var CHAR_SHARP = 0x23; /* # */ +var CHAR_PERCENT = 0x25; /* % */ +var CHAR_AMPERSAND = 0x26; /* & */ +var CHAR_SINGLE_QUOTE = 0x27; /* ' */ +var CHAR_ASTERISK = 0x2A; /* * */ +var CHAR_COMMA = 0x2C; /* , */ +var CHAR_MINUS = 0x2D; /* - */ +var CHAR_COLON = 0x3A; /* : */ +var CHAR_GREATER_THAN = 0x3E; /* > */ +var CHAR_QUESTION = 0x3F; /* ? */ +var CHAR_COMMERCIAL_AT = 0x40; /* @ */ +var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ +var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ +var CHAR_GRAVE_ACCENT = 0x60; /* ` */ +var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ +var CHAR_VERTICAL_LINE = 0x7C; /* | */ +var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + +var ESCAPE_SEQUENCES = {}; + +ESCAPE_SEQUENCES[0x00] = '\\0'; +ESCAPE_SEQUENCES[0x07] = '\\a'; +ESCAPE_SEQUENCES[0x08] = '\\b'; +ESCAPE_SEQUENCES[0x09] = '\\t'; +ESCAPE_SEQUENCES[0x0A] = '\\n'; +ESCAPE_SEQUENCES[0x0B] = '\\v'; +ESCAPE_SEQUENCES[0x0C] = '\\f'; +ESCAPE_SEQUENCES[0x0D] = '\\r'; +ESCAPE_SEQUENCES[0x1B] = '\\e'; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5C] = '\\\\'; +ESCAPE_SEQUENCES[0x85] = '\\N'; +ESCAPE_SEQUENCES[0xA0] = '\\_'; +ESCAPE_SEQUENCES[0x2028] = '\\L'; +ESCAPE_SEQUENCES[0x2029] = '\\P'; + +var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +]; + +function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; +} + +function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; +} + +function State(options) { + this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; + this.indent = Math.max(1, (options['indent'] || 2)); + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; +} + +function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); +} + +function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== 0xFEFF /* BOM */) + || (0x10000 <= c && c <= 0x10FFFF); +} + +// Simplified test for values allowed after the first character in plain style. +function isPlainSafe(c) { + // Uses a subset of nb-char - c-flow-indicator - ":" - "#" + // where nb-char ::= c-printable - b-char - c-byte-order-mark. + return isPrintable(c) && c !== 0xFEFF + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // - ":" - "#" + && c !== CHAR_COLON + && c !== CHAR_SHARP; +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + return isPrintable(c) && c !== 0xFEFF + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; +} + +var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { + var i; + var char; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(string.charCodeAt(0)) + && !isWhitespace(string.charCodeAt(string.length - 1)); + + if (singleLineOnly) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char); + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char); + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + return plain && !testAmbiguousType(string) + ? STYLE_PLAIN : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (string[0] === ' ' && indentPerLevel > 9) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar(state, string, level, iskey) { + state.dump = (function () { + if (string.length === 0) { + return "''"; + } + if (!state.noCompatMode && + DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) { + return "'" + string + "'"; + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) { + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string, lineWidth) + '"'; + default: + throw new YAMLException('impossible error: invalid scalar style'); + } + }()); +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader(string, indentPerLevel) { + var indentIndicator = (string[0] === ' ') ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; +} + +// (See the note for writeScalar.) +function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString(string) { + var result = ''; + var char; + var escapeSeq; + + for (var i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + escapeSeq = ESCAPE_SEQUENCES[char]; + result += !escapeSeq && isPrintable(char) + ? string[i] + : escapeSeq || encodeHex(char); + } + + return result; +} + +function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length; + + for (index = 0, length = object.length; index < length; index += 1) { + // Write only valid elements. + if (writeNode(state, level, object[index], false, false)) { + if (index !== 0) _result += ', '; + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; +} + +function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length; + + for (index = 0, length = object.length; index < length; index += 1) { + // Write only valid elements. + if (writeNode(state, level + 1, object[index], true, true)) { + if (!compact || index !== 0) { + _result += generateNextLine(state, level); + } + _result += '- ' + state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. +} + +function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (index !== 0) pairBuffer += ', '; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + ': '; + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; +} + +function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new YAMLException('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || index !== 0) { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. +} + +function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + state.tag = explicit ? type.tag : '?'; + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode(state, level, object, block, compact, iskey) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + writeBlockSequence(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey); + } + } else { + if (state.skipInvalid) return false; + throw new YAMLException('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + state.dump = '!<' + state.tag + '> ' + state.dump; + } + } + + return true; +} + +function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); +} + +function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } +} + +function dump(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + if (writeNode(state, 0, input, true, true)) return state.dump + '\n'; + + return ''; +} + +function safeDump(input, options) { + return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + +module.exports.dump = dump; +module.exports.safeDump = safeDump; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/exception.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/exception.js new file mode 100644 index 00000000..cf4e6252 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/exception.js @@ -0,0 +1,43 @@ +// YAML error class. http://stackoverflow.com/questions/8458984 +// +'use strict'; + +function YAMLException(reason, mark) { + // Super constructor + Error.call(this); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : ''); +} + + +// Inherit from Error +YAMLException.prototype = Object.create(Error.prototype); +YAMLException.prototype.constructor = YAMLException; + + +YAMLException.prototype.toString = function toString(compact) { + var result = this.name + ': '; + + result += this.reason || '(unknown reason)'; + + if (!compact && this.mark) { + result += ' ' + this.mark.toString(); + } + + return result; +}; + + +module.exports = YAMLException; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/loader.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/loader.js new file mode 100644 index 00000000..70e1a565 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/loader.js @@ -0,0 +1,1587 @@ +'use strict'; + +/*eslint-disable max-len,no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var Mark = require('./mark'); +var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe'); +var DEFAULT_FULL_SCHEMA = require('./schema/default_full'); + + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + + +var CONTEXT_FLOW_IN = 1; +var CONTEXT_FLOW_OUT = 2; +var CONTEXT_BLOCK_IN = 3; +var CONTEXT_BLOCK_OUT = 4; + + +var CHOMPING_CLIP = 1; +var CHOMPING_STRIP = 2; +var CHOMPING_KEEP = 3; + + +var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + +function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); +} + +function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); +} + +function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); +} + +function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; +} + +function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; +} + +function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; +} + +function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; +} + +function simpleEscapeSequence(c) { + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; +} + +function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode(((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00); +} + +var simpleEscapeCheck = new Array(256); // integer, for fast access +var simpleEscapeMap = new Array(256); +for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); +} + + +function State(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; + this.onWarning = options['onWarning'] || null; + this.legacy = options['legacy'] || false; + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + +} + + +function generateError(state, message) { + return new YAMLException( + message, + new Mark(state.filename, state.input, state.position, state.line, (state.position - state.lineStart))); +} + +function throwError(state, message) { + throw generateError(state, message); +} + +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} + + +var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + state.tagMap[handle] = prefix; + } +}; + + +function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; + _position < _length; + _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } +} + +function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} + +function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode) { + var index, quantity; + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty.call(overridableKeys, keyNode) && + _hasOwnProperty.call(_result, keyNode)) { + throwError(state, 'duplicated mapping key'); + } + _result[keyNode] = valueNode; + delete overridableKeys[keyNode]; + } + + return _result; +} + +function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; +} + +function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; +} + +function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; +} + +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } +} + + +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; +} + +function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); +} + +function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); +} + +function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = {}, + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); +} + +function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; +} + +function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; +} + +function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = {}, + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else { + break; // Reading is done. Go to the epilogue. + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if (state.lineIndent > nodeIndent && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; +} + +function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; +} + +function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; +} + +function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!state.anchorMap.hasOwnProperty(alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; +} + +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this<parent + atNewLine = false, + hasContent = false, + typeIndex, + typeQuantity, + type, + flowIndent, + blockIndent; + + if (state.listener !== null) { + state.listener('open', state); + } + + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + + allowBlockStyles = allowBlockScalars = allowBlockCollections = + CONTEXT_BLOCK_OUT === nodeContext || + CONTEXT_BLOCK_IN === nodeContext; + + if (allowToSeek) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag !== null && state.tag !== '!') { + if (state.tag === '?') { + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; + typeIndex < typeQuantity; + typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only assigned to plain scalars. So, it isn't + // needed to check for 'kind' conformity. + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} + +function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = {}; + state.anchorMap = {}; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } +} + + +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State(input, options); + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; +} + + +function loadAll(input, iterator, options) { + var documents = loadDocuments(input, options), index, length; + + for (index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } +} + + +function load(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new YAMLException('expected a single document in the stream, but found more'); +} + + +function safeLoadAll(input, output, options) { + loadAll(input, output, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + + +function safeLoad(input, options) { + return load(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + + +module.exports.loadAll = loadAll; +module.exports.load = load; +module.exports.safeLoadAll = safeLoadAll; +module.exports.safeLoad = safeLoad; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/mark.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/mark.js new file mode 100644 index 00000000..47b265c2 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/mark.js @@ -0,0 +1,76 @@ +'use strict'; + + +var common = require('./common'); + + +function Mark(name, buffer, position, line, column) { + this.name = name; + this.buffer = buffer; + this.position = position; + this.line = line; + this.column = column; +} + + +Mark.prototype.getSnippet = function getSnippet(indent, maxLength) { + var head, start, tail, end, snippet; + + if (!this.buffer) return null; + + indent = indent || 4; + maxLength = maxLength || 75; + + head = ''; + start = this.position; + + while (start > 0 && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(start - 1)) === -1) { + start -= 1; + if (this.position - start > (maxLength / 2 - 1)) { + head = ' ... '; + start += 5; + break; + } + } + + tail = ''; + end = this.position; + + while (end < this.buffer.length && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(end)) === -1) { + end += 1; + if (end - this.position > (maxLength / 2 - 1)) { + tail = ' ... '; + end -= 5; + break; + } + } + + snippet = this.buffer.slice(start, end); + + return common.repeat(' ', indent) + head + snippet + tail + '\n' + + common.repeat(' ', indent + this.position - start + head.length) + '^'; +}; + + +Mark.prototype.toString = function toString(compact) { + var snippet, where = ''; + + if (this.name) { + where += 'in "' + this.name + '" '; + } + + where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1); + + if (!compact) { + snippet = this.getSnippet(); + + if (snippet) { + where += ':\n' + snippet; + } + } + + return where; +}; + + +module.exports = Mark; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema.js new file mode 100644 index 00000000..ca7cf47e --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema.js @@ -0,0 +1,108 @@ +'use strict'; + +/*eslint-disable max-len*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var Type = require('./type'); + + +function compileList(schema, name, result) { + var exclude = []; + + schema.include.forEach(function (includedSchema) { + result = compileList(includedSchema, name, result); + }); + + schema[name].forEach(function (currentType) { + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) { + exclude.push(previousIndex); + } + }); + + result.push(currentType); + }); + + return result.filter(function (type, index) { + return exclude.indexOf(index) === -1; + }); +} + + +function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {} + }, index, length; + + function collectType(type) { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; +} + + +function Schema(definition) { + this.include = definition.include || []; + this.implicit = definition.implicit || []; + this.explicit = definition.explicit || []; + + this.implicit.forEach(function (type) { + if (type.loadKind && type.loadKind !== 'scalar') { + throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + }); + + this.compiledImplicit = compileList(this, 'implicit', []); + this.compiledExplicit = compileList(this, 'explicit', []); + this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit); +} + + +Schema.DEFAULT = null; + + +Schema.create = function createSchema() { + var schemas, types; + + switch (arguments.length) { + case 1: + schemas = Schema.DEFAULT; + types = arguments[0]; + break; + + case 2: + schemas = arguments[0]; + types = arguments[1]; + break; + + default: + throw new YAMLException('Wrong number of arguments for Schema.create function'); + } + + schemas = common.toArray(schemas); + types = common.toArray(types); + + if (!schemas.every(function (schema) { return schema instanceof Schema; })) { + throw new YAMLException('Specified list of super schemas (or a single Schema object) contains a non-Schema object.'); + } + + if (!types.every(function (type) { return type instanceof Type; })) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + return new Schema({ + include: schemas, + explicit: types + }); +}; + + +module.exports = Schema; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/core.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/core.js new file mode 100644 index 00000000..206daab5 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/core.js @@ -0,0 +1,18 @@ +// Standard YAML's Core schema. +// http://www.yaml.org/spec/1.2/spec.html#id2804923 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, Core schema has no distinctions from JSON schema is JS-YAML. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./json') + ] +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/default_full.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/default_full.js new file mode 100644 index 00000000..a55ef42a --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/default_full.js @@ -0,0 +1,25 @@ +// JS-YAML's default schema for `load` function. +// It is not described in the YAML specification. +// +// This schema is based on JS-YAML's default safe schema and includes +// JavaScript-specific types: !!js/undefined, !!js/regexp and !!js/function. +// +// Also this schema is used as default base schema at `Schema.create` function. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = Schema.DEFAULT = new Schema({ + include: [ + require('./default_safe') + ], + explicit: [ + require('../type/js/undefined'), + require('../type/js/regexp'), + require('../type/js/function') + ] +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/default_safe.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/default_safe.js new file mode 100644 index 00000000..11d89bbf --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/default_safe.js @@ -0,0 +1,28 @@ +// JS-YAML's default schema for `safeLoad` function. +// It is not described in the YAML specification. +// +// This schema is based on standard YAML's Core schema and includes most of +// extra types described at YAML tag repository. (http://yaml.org/type/) + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./core') + ], + implicit: [ + require('../type/timestamp'), + require('../type/merge') + ], + explicit: [ + require('../type/binary'), + require('../type/omap'), + require('../type/pairs'), + require('../type/set') + ] +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/failsafe.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/failsafe.js new file mode 100644 index 00000000..b7a33eb7 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/failsafe.js @@ -0,0 +1,17 @@ +// Standard YAML's Failsafe schema. +// http://www.yaml.org/spec/1.2/spec.html#id2802346 + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + explicit: [ + require('../type/str'), + require('../type/seq'), + require('../type/map') + ] +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/json.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/json.js new file mode 100644 index 00000000..5be3dbf8 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/schema/json.js @@ -0,0 +1,25 @@ +// Standard YAML's JSON schema. +// http://www.yaml.org/spec/1.2/spec.html#id2803231 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, this schema is not such strict as defined in the YAML specification. +// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./failsafe') + ], + implicit: [ + require('../type/null'), + require('../type/bool'), + require('../type/int'), + require('../type/float') + ] +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type.js new file mode 100644 index 00000000..90b702ac --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type.js @@ -0,0 +1,61 @@ +'use strict'; + +var YAMLException = require('./exception'); + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +module.exports = Type; diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/binary.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/binary.js new file mode 100644 index 00000000..205629f7 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/binary.js @@ -0,0 +1,135 @@ +'use strict'; + +/*eslint-disable no-bitwise*/ + +var NodeBuffer; + +try { + // A trick for browserified version, to not include `Buffer` shim + var _require = require; + NodeBuffer = _require('buffer').Buffer; +} catch (__) {} + +var Type = require('../type'); + + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + +function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; +} + +function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + // Wrap into Buffer for NodeJS and leave Array for browser + if (NodeBuffer) return new NodeBuffer(result); + + return result; +} + +function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; +} + +function isBinary(object) { + return NodeBuffer && NodeBuffer.isBuffer(object); +} + +module.exports = new Type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/bool.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/bool.js new file mode 100644 index 00000000..cb774593 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/bool.js @@ -0,0 +1,35 @@ +'use strict'; + +var Type = require('../type'); + +function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); +} + +function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; +} + +function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; +} + +module.exports = new Type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/float.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/float.js new file mode 100644 index 00000000..76871547 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/float.js @@ -0,0 +1,105 @@ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +var YAML_FLOAT_PATTERN = new RegExp( + '^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?' + + '|\\.[0-9_]+(?:[eE][-+][0-9]+)?' + + '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' + + '|[-+]?\\.(?:inf|Inf|INF)' + + '|\\.(?:nan|NaN|NAN))$'); + +function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data)) return false; + + return true; +} + +function constructYamlFloat(data) { + var value, sign, base, digits; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + digits = []; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + + } else if (value.indexOf(':') >= 0) { + value.split(':').forEach(function (v) { + digits.unshift(parseFloat(v, 10)); + }); + + value = 0.0; + base = 1; + + digits.forEach(function (d) { + value += d * base; + base *= 60; + }); + + return sign * value; + + } + return sign * parseFloat(value, 10); +} + + +var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; +} + +function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/int.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/int.js new file mode 100644 index 00000000..a3c49650 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/int.js @@ -0,0 +1,168 @@ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); +} + +function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); +} + +function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); +} + +function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits; + } + + // base 8 + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits; + } + + // base 10 (except 0) or base 60 + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch === ':') break; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + if (!hasDigits) return false; + + // if !base60 - done; + if (ch !== ':') return true; + + // base60 almost not used, no needs to optimize + return /^(:[0-5]?[0-9])+$/.test(data.slice(index)); +} + +function constructYamlInteger(data) { + var value = data, sign = 1, ch, base, digits = []; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value, 16); + return sign * parseInt(value, 8); + } + + if (value.indexOf(':') !== -1) { + value.split(':').forEach(function (v) { + digits.unshift(parseInt(v, 10)); + }); + + value = 0; + base = 1; + + digits.forEach(function (d) { + value += (d * base); + base *= 60; + }); + + return sign * value; + + } + + return sign * parseInt(value, 10); +} + +function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (object) { return '0b' + object.toString(2); }, + octal: function (object) { return '0' + object.toString(8); }, + decimal: function (object) { return object.toString(10); }, + hexadecimal: function (object) { return '0x' + object.toString(16).toUpperCase(); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/function.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/function.js new file mode 100644 index 00000000..c6a42d00 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/function.js @@ -0,0 +1,84 @@ +'use strict'; + +var esprima; + +// Browserified version does not have esprima +// +// 1. For node.js just require module as deps +// 2. For browser try to require mudule via external AMD system. +// If not found - try to fallback to window.esprima. If not +// found too - then fail to parse. +// +try { + // workaround to exclude package from browserify list. + var _require = require; + esprima = _require('esprima'); +} catch (_) { + /*global window */ + if (typeof window !== 'undefined') esprima = window.esprima; +} + +var Type = require('../../type'); + +function resolveJavascriptFunction(data) { + if (data === null) return false; + + try { + var source = '(' + data + ')', + ast = esprima.parse(source, { range: true }); + + if (ast.type !== 'Program' || + ast.body.length !== 1 || + ast.body[0].type !== 'ExpressionStatement' || + ast.body[0].expression.type !== 'FunctionExpression') { + return false; + } + + return true; + } catch (err) { + return false; + } +} + +function constructJavascriptFunction(data) { + /*jslint evil:true*/ + + var source = '(' + data + ')', + ast = esprima.parse(source, { range: true }), + params = [], + body; + + if (ast.type !== 'Program' || + ast.body.length !== 1 || + ast.body[0].type !== 'ExpressionStatement' || + ast.body[0].expression.type !== 'FunctionExpression') { + throw new Error('Failed to resolve function'); + } + + ast.body[0].expression.params.forEach(function (param) { + params.push(param.name); + }); + + body = ast.body[0].expression.body.range; + + // Esprima's ranges include the first '{' and the last '}' characters on + // function expressions. So cut them out. + /*eslint-disable no-new-func*/ + return new Function(params, source.slice(body[0] + 1, body[1] - 1)); +} + +function representJavascriptFunction(object /*, style*/) { + return object.toString(); +} + +function isFunction(object) { + return Object.prototype.toString.call(object) === '[object Function]'; +} + +module.exports = new Type('tag:yaml.org,2002:js/function', { + kind: 'scalar', + resolve: resolveJavascriptFunction, + construct: constructJavascriptFunction, + predicate: isFunction, + represent: representJavascriptFunction +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/regexp.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/regexp.js new file mode 100644 index 00000000..43fa4701 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/regexp.js @@ -0,0 +1,60 @@ +'use strict'; + +var Type = require('../../type'); + +function resolveJavascriptRegExp(data) { + if (data === null) return false; + if (data.length === 0) return false; + + var regexp = data, + tail = /\/([gim]*)$/.exec(data), + modifiers = ''; + + // if regexp starts with '/' it can have modifiers and must be properly closed + // `/foo/gim` - modifiers tail can be maximum 3 chars + if (regexp[0] === '/') { + if (tail) modifiers = tail[1]; + + if (modifiers.length > 3) return false; + // if expression starts with /, is should be properly terminated + if (regexp[regexp.length - modifiers.length - 1] !== '/') return false; + } + + return true; +} + +function constructJavascriptRegExp(data) { + var regexp = data, + tail = /\/([gim]*)$/.exec(data), + modifiers = ''; + + // `/foo/gim` - tail can be maximum 4 chars + if (regexp[0] === '/') { + if (tail) modifiers = tail[1]; + regexp = regexp.slice(1, regexp.length - modifiers.length - 1); + } + + return new RegExp(regexp, modifiers); +} + +function representJavascriptRegExp(object /*, style*/) { + var result = '/' + object.source + '/'; + + if (object.global) result += 'g'; + if (object.multiline) result += 'm'; + if (object.ignoreCase) result += 'i'; + + return result; +} + +function isRegExp(object) { + return Object.prototype.toString.call(object) === '[object RegExp]'; +} + +module.exports = new Type('tag:yaml.org,2002:js/regexp', { + kind: 'scalar', + resolve: resolveJavascriptRegExp, + construct: constructJavascriptRegExp, + predicate: isRegExp, + represent: representJavascriptRegExp +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/undefined.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/undefined.js new file mode 100644 index 00000000..95b5569f --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/js/undefined.js @@ -0,0 +1,28 @@ +'use strict'; + +var Type = require('../../type'); + +function resolveJavascriptUndefined() { + return true; +} + +function constructJavascriptUndefined() { + /*eslint-disable no-undefined*/ + return undefined; +} + +function representJavascriptUndefined() { + return ''; +} + +function isUndefined(object) { + return typeof object === 'undefined'; +} + +module.exports = new Type('tag:yaml.org,2002:js/undefined', { + kind: 'scalar', + resolve: resolveJavascriptUndefined, + construct: constructJavascriptUndefined, + predicate: isUndefined, + represent: representJavascriptUndefined +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/map.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/map.js new file mode 100644 index 00000000..f327beeb --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/map.js @@ -0,0 +1,8 @@ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/merge.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/merge.js new file mode 100644 index 00000000..ae08a864 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/merge.js @@ -0,0 +1,12 @@ +'use strict'; + +var Type = require('../type'); + +function resolveYamlMerge(data) { + return data === '<<' || data === null; +} + +module.exports = new Type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/null.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/null.js new file mode 100644 index 00000000..6874daa6 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/null.js @@ -0,0 +1,34 @@ +'use strict'; + +var Type = require('../type'); + +function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); +} + +function constructYamlNull() { + return null; +} + +function isNull(object) { + return object === null; +} + +module.exports = new Type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; } + }, + defaultStyle: 'lowercase' +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/omap.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/omap.js new file mode 100644 index 00000000..b2b5323b --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/omap.js @@ -0,0 +1,44 @@ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; +var _toString = Object.prototype.toString; + +function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; +} + +function constructYamlOmap(data) { + return data !== null ? data : []; +} + +module.exports = new Type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/pairs.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/pairs.js new file mode 100644 index 00000000..74b52403 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/pairs.js @@ -0,0 +1,53 @@ +'use strict'; + +var Type = require('../type'); + +var _toString = Object.prototype.toString; + +function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; +} + +function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; +} + +module.exports = new Type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/seq.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/seq.js new file mode 100644 index 00000000..be8f77f2 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/seq.js @@ -0,0 +1,8 @@ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/set.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/set.js new file mode 100644 index 00000000..f885a329 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/set.js @@ -0,0 +1,29 @@ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data) { + return data !== null ? data : {}; +} + +module.exports = new Type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/str.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/str.js new file mode 100644 index 00000000..27acc106 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/str.js @@ -0,0 +1,8 @@ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } +}); diff --git a/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/timestamp.js b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/timestamp.js new file mode 100644 index 00000000..8fa9c586 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/lib/js-yaml/type/timestamp.js @@ -0,0 +1,88 @@ +'use strict'; + +var Type = require('../type'); + +var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + +var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} + +function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; +} + +function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); +} + +module.exports = new Type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}); diff --git a/node_modules/svgo/node_modules/js-yaml/node_modules/.bin/esparse b/node_modules/svgo/node_modules/js-yaml/node_modules/.bin/esparse new file mode 120000 index 00000000..d3e4b572 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/node_modules/.bin/esparse @@ -0,0 +1 @@ +../../../esprima/bin/esparse.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/js-yaml/node_modules/.bin/esvalidate b/node_modules/svgo/node_modules/js-yaml/node_modules/.bin/esvalidate new file mode 120000 index 00000000..f8ef4b99 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/node_modules/.bin/esvalidate @@ -0,0 +1 @@ +../../../esprima/bin/esvalidate.js
\ No newline at end of file diff --git a/node_modules/svgo/node_modules/js-yaml/package.json b/node_modules/svgo/node_modules/js-yaml/package.json new file mode 100644 index 00000000..1c6deb19 --- /dev/null +++ b/node_modules/svgo/node_modules/js-yaml/package.json @@ -0,0 +1,46 @@ +{ + "name": "js-yaml", + "version": "3.7.0", + "description": "YAML 1.2 parser and serializer", + "keywords": [ + "yaml", + "parser", + "serializer", + "pyyaml" + ], + "homepage": "https://github.com/nodeca/js-yaml", + "author": "Vladimir Zapparov <dervus.grim@gmail.com>", + "contributors": [ + "Aleksey V Zapparov <ixti@member.fsf.org> (http://www.ixti.net/)", + "Vitaly Puzrin <vitaly@rcdesign.ru> (https://github.com/puzrin)", + "Martin Grenfell <martin.grenfell@gmail.com> (http://got-ravings.blogspot.com)" + ], + "license": "MIT", + "repository": "nodeca/js-yaml", + "files": [ + "index.js", + "lib/", + "bin/", + "dist/" + ], + "bin": { + "js-yaml": "bin/js-yaml.js" + }, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + }, + "devDependencies": { + "ansi": "*", + "benchmark": "*", + "browserify": "^13.0.0", + "codemirror": "^5.13.4", + "eslint": "^2.8.0", + "istanbul": "*", + "mocha": "*", + "uglify-js": "^2.6.1" + }, + "scripts": { + "test": "make test" + } +} diff --git a/node_modules/svgo/package.json b/node_modules/svgo/package.json new file mode 100644 index 00000000..be1eee49 --- /dev/null +++ b/node_modules/svgo/package.json @@ -0,0 +1,70 @@ +{ + "name": "svgo", + "version": "0.7.2", + "description": "Nodejs-based tool for optimizing SVG vector graphics files", + "keywords": [ + "svgo", + "svg", + "optimize", + "minify" + ], + "homepage": "https://github.com/svg/svgo", + "bugs": { + "url": "https://github.com/svg/svgo/issues", + "email": "kir@soulshine.in" + }, + "author": { + "name": "Kir Belevich", + "email": "kir@soulshine.in", + "url": "https://github.com/deepsweet" + }, + "contributors": [ + { + "name": "Sergey Belov", + "email": "peimei@ya.ru", + "url": "http://github.com/arikon" + }, + { + "name": "Lev Solntsev", + "email": "lev.sun@ya.ru", + "url": "http://github.com/GreLI" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/svg/svgo.git" + }, + "main": "./lib/svgo.js", + "bin": { + "svgo": "./bin/svgo" + }, + "directories": { + "bin": "./bin", + "lib": "./lib", + "example": "./examples" + }, + "scripts": { + "test": "set NODE_ENV=test && mocha", + "jshint": "jshint --show-non-errors ." + }, + "dependencies": { + "sax": "~1.2.1", + "coa": "~1.0.1", + "js-yaml": "~3.7.0", + "colors": "~1.1.2", + "whet.extend": "~0.9.9", + "mkdirp": "~0.5.1", + "csso": "~2.3.1" + }, + "devDependencies": { + "mocha": "~3.2.0", + "should": "11.2.0", + "istanbul": "~0.4.5", + "mocha-istanbul": "~0.3.0", + "coveralls": "~2.11.14" + }, + "engines": { + "node": ">=0.10.0" + }, + "license": "MIT" +} diff --git a/node_modules/svgo/plugins/_collections.js b/node_modules/svgo/plugins/_collections.js new file mode 100644 index 00000000..8ff3d1fb --- /dev/null +++ b/node_modules/svgo/plugins/_collections.js @@ -0,0 +1,2529 @@ +'use strict'; + +// http://www.w3.org/TR/SVG/intro.html#Definitions +exports.elemsGroups = { + animation: ['animate', 'animateColor', 'animateMotion', 'animateTransform', 'set'], + descriptive: ['desc', 'metadata', 'title'], + shape: ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'], + structural: ['defs', 'g', 'svg', 'symbol', 'use'], + paintServer: ['solidColor', 'linearGradient', 'radialGradient', 'meshGradient', 'pattern', 'hatch'], + nonRendering: ['linearGradient', 'radialGradient', 'pattern', 'clipPath', 'mask', 'marker', 'symbol', 'filter', 'solidColor'], + container: ['a', 'defs', 'g', 'marker', 'mask', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol', 'foreignObject'], + textContent: ['altGlyph', 'altGlyphDef', 'altGlyphItem', 'glyph', 'glyphRef', 'textPath', 'text', 'tref', 'tspan'], + textContentChild: ['altGlyph', 'textPath', 'tref', 'tspan'], + lightSource: ['feDiffuseLighting', 'feSpecularLighting', 'feDistantLight', 'fePointLight', 'feSpotLight'], + filterPrimitive: ['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feFlood', 'feGaussianBlur', 'feImage', 'feMerge', 'feMorphology', 'feOffset', 'feSpecularLighting', 'feTile', 'feTurbulence'] +}; + +exports.pathElems = ['path', 'glyph', 'missing-glyph']; + +// http://www.w3.org/TR/SVG/intro.html#Definitions +exports.attrsGroups = { + animationAddition: ['additive', 'accumulate'], + animationAttributeTarget: ['attributeType', 'attributeName'], + animationEvent: ['onbegin', 'onend', 'onrepeat', 'onload'], + animationTiming: ['begin', 'dur', 'end', 'min', 'max', 'restart', 'repeatCount', 'repeatDur', 'fill'], + animationValue: ['calcMode', 'values', 'keyTimes', 'keySplines', 'from', 'to', 'by'], + conditionalProcessing: ['requiredFeatures', 'requiredExtensions', 'systemLanguage'], + core: ['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space'], + graphicalEvent: ['onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload'], + presentation: [ + 'alignment-baseline', + 'baseline-shift', + 'buffered-rendering', + 'clip', + 'clip-path', + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'cursor', + 'direction', + 'display', + 'dominant-baseline', + 'enable-background', + 'fill', + 'fill-opacity', + 'fill-rule', + 'filter', + 'flood-color', + 'flood-opacity', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-style', + 'font-variant', + 'font-weight', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'image-rendering', + 'kerning', + 'letter-spacing', + 'lighting-color', + 'marker-end', + 'marker-mid', + 'marker-start', + 'mask', + 'opacity', + 'overflow', + 'pointer-events', + 'shape-rendering', + 'solid-color', + 'solid-opacity', + 'stop-color', + 'stop-opacity', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'paint-order', + 'text-anchor', + 'text-decoration', + 'text-overflow', + 'white-space', + 'text-rendering', + 'unicode-bidi', + 'vector-effect', + 'viewport-fill', + 'viewport-fill-opacity', + 'visibility', + 'white-space', + 'word-spacing', + 'writing-mode' + ], + xlink: ['xlink:href', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title'], + documentEvent: ['onunload', 'onabort', 'onerror', 'onresize', 'onscroll', 'onzoom'], + filterPrimitive: ['x', 'y', 'width', 'height', 'result'], + transferFunction: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset'] +}; + +exports.attrsGroupsDefaults = { + core: {'xml:space': 'preserve'}, + filterPrimitive: {x: '0', y: '0', width: '100%', height: '100%'}, + presentation: { + clip: 'auto', + 'clip-path': 'none', + 'clip-rule': 'nonzero', + mask: 'none', + opacity: '1', + 'solid-color': '#000', + 'solid-opacity': '1', + 'stop-color': '#000', + 'stop-opacity': '1', + 'fill-opacity': '1', + 'fill-rule': 'nonzero', + fill: '#000', + stroke: 'none', + 'stroke-width': '1', + 'stroke-linecap': 'butt', + 'stroke-linejoin': 'miter', + 'stroke-miterlimit': '4', + 'stroke-dasharray': 'none', + 'stroke-dashoffset': '0', + 'stroke-opacity': '1', + 'paint-order': 'normal', + 'vector-effect': 'none', + 'viewport-fill': 'none', + 'viewport-fill-opacity': '1', + display: 'inline', + visibility: 'visible', + 'marker-start': 'none', + 'marker-mid': 'none', + 'marker-end': 'none', + 'color-interpolation': 'sRGB', + 'color-interpolation-filters': 'linearRGB', + 'color-rendering': 'auto', + 'shape-rendering': 'auto', + 'text-rendering': 'auto', + 'image-rendering': 'auto', + 'buffered-rendering': 'auto', + 'font-style': 'normal', + 'font-variant': 'normal', + 'font-weight': 'normal', + 'font-stretch': 'normal', + 'font-size': 'medium', + 'font-size-adjust': 'none', + kerning: 'auto', + 'letter-spacing': 'normal', + 'word-spacing': 'normal', + 'text-decoration': 'none', + 'text-anchor': 'start', + 'text-overflow': 'clip', + 'writing-mode': 'lr-tb', + 'glyph-orientation-vertical': 'auto', + 'glyph-orientation-horizontal': '0deg', + direction: 'ltr', + 'unicode-bidi': 'normal', + 'dominant-baseline': 'auto', + 'alignment-baseline': 'baseline', + 'baseline-shift': 'baseline' + }, + transferFunction: {slope: '1', intercept: '0', amplitude: '1', exponent: '1', offset: '0'} +}; + +// http://www.w3.org/TR/SVG/eltindex.html +exports.elems = { + a: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'target' + ], + defaults: { + target: '_self' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + altGlyph: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'dx', + 'dy', + 'glyphRef', + 'format', + 'rotate' + ] + }, + altGlyphDef: { + attrsGroups: [ + 'core' + ], + content: [ + 'glyphRef' + ] + }, + altGlyphItem: { + attrsGroups: [ + 'core' + ], + content: [ + 'glyphRef', + 'altGlyphItem' + ] + }, + animate: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationAddition', + 'animationAttributeTarget', + 'animationEvent', + 'animationTiming', + 'animationValue', + 'presentation', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired' + ], + contentGroups: [ + 'descriptive' + ] + }, + animateColor: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + 'animationValue', + 'animationAddition', + 'presentation' + ], + attrs: [ + 'externalResourcesRequired' + ], + contentGroups: [ + 'descriptive' + ] + }, + animateMotion: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationTiming', + 'animationValue', + 'animationAddition' + ], + attrs: [ + 'externalResourcesRequired', + 'path', + 'keyPoints', + 'rotate', + 'origin' + ], + defaults: { + 'rotate': '0' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'mpath' + ] + }, + animateTransform: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + 'animationValue', + 'animationAddition' + ], + attrs: [ + 'externalResourcesRequired', + 'type' + ], + contentGroups: [ + 'descriptive' + ] + }, + circle: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'cx', + 'cy', + 'r' + ], + defaults: { + cx: '0', + cy: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + clipPath: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'clipPathUnits' + ], + defaults: { + clipPathUnits: 'userSpaceOnUse' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape' + ], + content: [ + 'text', + 'use' + ] + }, + 'color-profile': { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'local', + 'name', + 'rendering-intent' + ], + defaults: { + name: 'sRGB', + 'rendering-intent': 'auto' + }, + contentGroups: [ + 'descriptive' + ] + }, + cursor: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired', + 'x', + 'y' + ], + defaults: { + x: '0', + y: '0' + }, + contentGroups: [ + 'descriptive' + ] + }, + defs: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + desc: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'class', + 'style' + ] + }, + ellipse: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'cx', + 'cy', + 'rx', + 'ry' + ], + defaults: { + cx: '0', + cy: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + feBlend: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + // TODO: in - 'If no value is provided and this is the first filter primitive, + // then this filter primitive will use SourceGraphic as its input' + 'in', + 'in2', + 'mode' + ], + defaults: { + mode: 'normal' + }, + content: [ + 'animate', + 'set' + ] + }, + feColorMatrix: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'type', + 'values' + ], + defaults: { + type: 'matrix' + }, + content: [ + 'animate', + 'set' + ] + }, + feComponentTransfer: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in' + ], + content: [ + 'feFuncA', + 'feFuncB', + 'feFuncG', + 'feFuncR' + ] + }, + feComposite: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'in2', + 'operator', + 'k1', + 'k2', + 'k3', + 'k4' + ], + defaults: { + operator: 'over', + k1: '0', + k2: '0', + k3: '0', + k4: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feConvolveMatrix: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'order', + 'kernelMatrix', + // TODO: divisor - 'The default value is the sum of all values in kernelMatrix, + // with the exception that if the sum is zero, then the divisor is set to 1' + 'divisor', + 'bias', + // TODO: targetX - 'By default, the convolution matrix is centered in X over each + // pixel of the input image (i.e., targetX = floor ( orderX / 2 ))' + 'targetX', + 'targetY', + 'edgeMode', + // TODO: kernelUnitLength - 'The first number is the <dx> value. The second number + // is the <dy> value. If the <dy> value is not specified, it defaults to the same value as <dx>' + 'kernelUnitLength', + 'preserveAlpha' + ], + defaults: { + order: '3', + bias: '0', + edgeMode: 'duplicate', + preserveAlpha: 'false' + }, + content: [ + 'animate', + 'set' + ] + }, + feDiffuseLighting: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'surfaceScale', + 'diffuseConstant', + 'kernelUnitLength' + ], + defaults: { + surfaceScale: '1', + diffuseConstant: '1' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + // TODO: 'exactly one light source element, in any order' + 'feDistantLight', + 'fePointLight', + 'feSpotLight' + ] + }, + feDisplacementMap: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'in2', + 'scale', + 'xChannelSelector', + 'yChannelSelector' + ], + defaults: { + scale: '0', + xChannelSelector: 'A', + yChannelSelector: 'A' + }, + content: [ + 'animate', + 'set' + ] + }, + feDistantLight: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'azimuth', + 'elevation' + ], + defaults: { + azimuth: '0', + elevation: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feFlood: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style' + ], + content: [ + 'animate', + 'animateColor', + 'set' + ] + }, + feFuncA: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feFuncB: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feFuncG: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feFuncR: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feGaussianBlur: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'stdDeviation' + ], + defaults: { + stdDeviation: '0' + }, + content: [ + 'set', + 'animate' + ] + }, + feImage: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'xlink:href' + ], + defaults: { + preserveAspectRatio: 'xMidYMid meet' + }, + content: [ + 'animate', + 'animateTransform', + 'set' + ] + }, + feMerge: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style' + ], + content: [ + 'feMergeNode' + ] + }, + feMergeNode: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'in' + ], + content: [ + 'animate', + 'set' + ] + }, + feMorphology: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'operator', + 'radius' + ], + defaults: { + operator: 'erode', + radius: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feOffset: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'dx', + 'dy' + ], + defaults: { + dx: '0', + dy: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + fePointLight: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'x', + 'y', + 'z' + ], + defaults: { + x: '0', + y: '0', + z: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feSpecularLighting: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'surfaceScale', + 'specularConstant', + 'specularExponent', + 'kernelUnitLength' + ], + defaults: { + surfaceScale: '1', + specularConstant: '1', + specularExponent: '1' + }, + contentGroups: [ + 'descriptive', + // TODO: exactly one 'light source element' + 'lightSource' + ] + }, + feSpotLight: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'x', + 'y', + 'z', + 'pointsAtX', + 'pointsAtY', + 'pointsAtZ', + 'specularExponent', + 'limitingConeAngle' + ], + defaults: { + x: '0', + y: '0', + z: '0', + pointsAtX: '0', + pointsAtY: '0', + pointsAtZ: '0', + specularExponent: '1' + }, + content: [ + 'animate', + 'set' + ] + }, + feTile: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in' + ], + content: [ + 'animate', + 'set' + ] + }, + feTurbulence: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'baseFrequency', + 'numOctaves', + 'seed', + 'stitchTiles', + 'type' + ], + defaults: { + baseFrequency: '0', + numOctaves: '1', + seed: '0', + stitchTiles: 'noStitch', + type: 'turbulence' + }, + content: [ + 'animate', + 'set' + ] + }, + filter: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'width', + 'height', + 'filterRes', + 'filterUnits', + 'primitiveUnits', + 'xlink:href' + ], + defaults: { + primitiveUnits: 'userSpaceOnUse', + x: '-10%', + y: '-10%', + width: '120%', + height: '120%' + }, + contentGroups: [ + 'descriptive', + 'filterPrimitive' + ], + content: [ + 'animate', + 'set' + ] + }, + font: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'horiz-origin-x', + 'horiz-origin-y', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y' + ], + defaults: { + 'horiz-origin-x': '0', + 'horiz-origin-y': '0' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'font-face', + 'glyph', + 'hkern', + 'missing-glyph', + 'vkern' + ] + }, + 'font-face': { + attrsGroups: [ + 'core' + ], + attrs: [ + 'font-family', + 'font-style', + 'font-variant', + 'font-weight', + 'font-stretch', + 'font-size', + 'unicode-range', + 'units-per-em', + 'panose-1', + 'stemv', + 'stemh', + 'slope', + 'cap-height', + 'x-height', + 'accent-height', + 'ascent', + 'descent', + 'widths', + 'bbox', + 'ideographic', + 'alphabetic', + 'mathematical', + 'hanging', + 'v-ideographic', + 'v-alphabetic', + 'v-mathematical', + 'v-hanging', + 'underline-position', + 'underline-thickness', + 'strikethrough-position', + 'strikethrough-thickness', + 'overline-position', + 'overline-thickness' + ], + defaults: { + 'font-style': 'all', + 'font-variant': 'normal', + 'font-weight': 'all', + 'font-stretch': 'normal', + 'unicode-range': 'U+0-10FFFF', + 'units-per-em': '1000', + 'panose-1': '0 0 0 0 0 0 0 0 0 0', + 'slope': '0' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + // TODO: "at most one 'font-face-src' element" + 'font-face-src' + ] + }, + // TODO: empty content + 'font-face-format': { + attrsGroups: [ + 'core' + ], + attrs: [ + 'string' + ] + }, + 'font-face-name': { + attrsGroups: [ + 'core' + ], + attrs: [ + 'name' + ] + }, + 'font-face-src': { + attrsGroups: [ + 'core' + ], + content: [ + 'font-face-name', + 'font-face-uri' + ] + }, + 'font-face-uri': { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'xlink:href' + ], + content: [ + 'font-face-format' + ] + }, + foreignObject: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height' + ], + defaults: { + x: 0, + y: 0 + } + }, + g: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + glyph: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y', + 'unicode', + 'glyph-name', + 'orientation', + 'arabic-form', + 'lang' + ], + defaults: { + 'arabic-form': 'initial' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ], + }, + glyphRef: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + hatch: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'pitch', + 'rotate', + 'hatchUnits', + 'hatchContentUnits', + 'transform' + ], + defaults: { + hatchUnits: 'objectBoundingBox', + hatchContentUnits: 'userSpaceOnUse', + x: '0', + y: '0', + pitch: '0', + rotate: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ], + content: [ + 'hatchPath' + ] + }, + hatchPath: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'd', + 'offset' + ], + defaults: { + offset: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + hkern: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'u1', + 'g1', + 'u2', + 'g2', + 'k' + ] + }, + image: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'xlink', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'xlink:href' + ], + defaults: { + x: '0', + y: '0', + preserveAspectRatio: 'xMidYMid meet' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + line: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x1', + 'y1', + 'x2', + 'y2' + ], + defaults: { + x1: '0', + y1: '0', + x2: '0', + y2: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + linearGradient: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x1', + 'y1', + 'x2', + 'y2', + 'gradientUnits', + 'gradientTransform', + 'spreadMethod', + 'xlink:href' + ], + defaults: { + x1: '0', + y1: '0', + x2: '100%', + y2: '0', + spreadMethod: 'pad' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'animate', + 'animateTransform', + 'set', + 'stop' + ] + }, + marker: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'refX', + 'refY', + 'markerUnits', + 'markerWidth', + 'markerHeight', + 'orient' + ], + defaults: { + markerUnits: 'strokeWidth', + refX: '0', + refY: '0', + markerWidth: '3', + markerHeight: '3' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + mask: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'width', + 'height', + 'maskUnits', + 'maskContentUnits' + ], + defaults: { + maskUnits: 'objectBoundingBox', + maskContentUnits: 'userSpaceOnUse', + x: '-10%', + y: '-10%', + width: '120%', + height: '120%' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + metadata: { + attrsGroups: [ + 'core' + ] + }, + 'missing-glyph': { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + mpath: { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired', + 'xlink:href' + ], + contentGroups: [ + 'descriptive' + ] + }, + path: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'd', + 'pathLength' + ], + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + pattern: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'x', + 'y', + 'width', + 'height', + 'patternUnits', + 'patternContentUnits', + 'patternTransform', + 'xlink:href' + ], + defaults: { + patternUnits: 'objectBoundingBox', + patternContentUnits: 'userSpaceOnUse', + x: '0', + y: '0', + width: '0', + height: '0', + preserveAspectRatio: 'xMidYMid meet' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'paintServer', + 'shape', + 'structural' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + polygon: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'points' + ], + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + polyline: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'points' + ], + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + radialGradient: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'cx', + 'cy', + 'r', + 'fx', + 'fy', + 'fr', + 'gradientUnits', + 'gradientTransform', + 'spreadMethod', + 'xlink:href' + ], + defaults: { + gradientUnits: 'objectBoundingBox', + cx: '50%', + cy: '50%', + r: '50%' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'animate', + 'animateTransform', + 'set', + 'stop' + ] + }, + meshGradient: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'gradientUnits', + 'transform' + ], + contentGroups: [ + 'descriptive', + 'paintServer', + 'animation', + ], + content: [ + 'meshRow' + ] + }, + meshRow: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'meshPatch' + ] + }, + meshPatch: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'stop' + ] + }, + rect: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'rx', + 'ry' + ], + defaults: { + x: '0', + y: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + script: { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired', + 'type', + 'xlink:href' + ] + }, + set: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animation', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + ], + attrs: [ + 'externalResourcesRequired', + 'to' + ], + contentGroups: [ + 'descriptive' + ] + }, + solidColor: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style' + ], + contentGroups: [ + 'paintServer' + ] + }, + stop: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'offset', + 'path' + ], + content: [ + 'animate', + 'animateColor', + 'set' + ] + }, + style: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'type', + 'media', + 'title' + ], + defaults: { + type: 'text/css' + } + }, + svg: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'documentEvent', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'width', + 'height', + 'viewBox', + 'preserveAspectRatio', + 'zoomAndPan', + 'version', + 'baseProfile', + 'contentScriptType', + 'contentStyleType' + ], + defaults: { + x: '0', + y: '0', + width: '100%', + height: '100%', + preserveAspectRatio: 'xMidYMid meet', + zoomAndPan: 'magnify', + version: '1.1', + baseProfile: 'none', + contentScriptType: 'application/ecmascript', + contentStyleType: 'text/css' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + switch: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape' + ], + content: [ + 'a', + 'foreignObject', + 'g', + 'image', + 'svg', + 'switch', + 'text', + 'use' + ] + }, + symbol: { + attrsGroups: [ + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'viewBox', + 'refX', + 'refY' + ], + defaults: { + refX: 0, + refY: 0 + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + text: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'lengthAdjust', + 'x', + 'y', + 'dx', + 'dy', + 'rotate', + 'textLength' + ], + defaults: { + x: '0', + y: '0', + lengthAdjust: 'spacing' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'textContentChild' + ], + content: [ + 'a' + ] + }, + textPath: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'xlink:href', + 'startOffset', + 'method', + 'spacing', + 'd' + ], + defaults: { + startOffset: '0', + method: 'align', + spacing: 'exact' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'a', + 'altGlyph', + 'animate', + 'animateColor', + 'set', + 'tref', + 'tspan' + ] + }, + title: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'class', + 'style' + ] + }, + tref: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'xlink:href' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'animate', + 'animateColor', + 'set' + ] + }, + tspan: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'dx', + 'dy', + 'rotate', + 'textLength', + 'lengthAdjust' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'a', + 'altGlyph', + 'animate', + 'animateColor', + 'set', + 'tref', + 'tspan' + ] + }, + use: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'xlink:href' + ], + defaults: { + x: '0', + y: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + view: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'zoomAndPan', + 'viewTarget' + ], + contentGroups: [ + 'descriptive' + ] + }, + vkern: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'u1', + 'g1', + 'u2', + 'g2', + 'k' + ] + } +}; + +// http://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes +exports.editorNamespaces = [ + 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd', + 'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd', + 'http://www.inkscape.org/namespaces/inkscape', + 'http://www.bohemiancoding.com/sketch/ns', + 'http://ns.adobe.com/AdobeIllustrator/10.0/', + 'http://ns.adobe.com/Graphs/1.0/', + 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/', + 'http://ns.adobe.com/Variables/1.0/', + 'http://ns.adobe.com/SaveForWeb/1.0/', + 'http://ns.adobe.com/Extensibility/1.0/', + 'http://ns.adobe.com/Flows/1.0/', + 'http://ns.adobe.com/ImageReplacement/1.0/', + 'http://ns.adobe.com/GenericCustomNamespace/1.0/', + 'http://ns.adobe.com/XPath/1.0/' +]; + +// http://www.w3.org/TR/SVG/linking.html#processingIRI +exports.referencesProps = [ + 'clip-path', + 'color-profile', + 'fill', + 'filter', + 'marker-start', + 'marker-mid', + 'marker-end', + 'mask', + 'stroke', + 'style' +]; + +// http://www.w3.org/TR/SVG/propidx.html +exports.inheritableAttrs = [ + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'cursor', + 'direction', + 'fill', + 'fill-opacity', + 'fill-rule', + 'font', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-style', + 'font-variant', + 'font-weight', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'image-rendering', + 'kerning', + 'letter-spacing', + 'marker', + 'marker-end', + 'marker-mid', + 'marker-start', + 'pointer-events', + 'shape-rendering', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'text-anchor', + 'text-rendering', + 'transform', + 'visibility', + 'white-space', + 'word-spacing', + 'writing-mode' +]; + +// http://www.w3.org/TR/SVG/single-page.html#types-ColorKeywords +exports.colorsNames = { + 'aliceblue': '#f0f8ff', + 'antiquewhite': '#faebd7', + 'aqua': '#0ff', + 'aquamarine': '#7fffd4', + 'azure': '#f0ffff', + 'beige': '#f5f5dc', + 'bisque': '#ffe4c4', + 'black': '#000', + 'blanchedalmond': '#ffebcd', + 'blue': '#00f', + 'blueviolet': '#8a2be2', + 'brown': '#a52a2a', + 'burlywood': '#deb887', + 'cadetblue': '#5f9ea0', + 'chartreuse': '#7fff00', + 'chocolate': '#d2691e', + 'coral': '#ff7f50', + 'cornflowerblue': '#6495ed', + 'cornsilk': '#fff8dc', + 'crimson': '#dc143c', + 'cyan': '#0ff', + 'darkblue': '#00008b', + 'darkcyan': '#008b8b', + 'darkgoldenrod': '#b8860b', + 'darkgray': '#a9a9a9', + 'darkgreen': '#006400', + 'darkkhaki': '#bdb76b', + 'darkmagenta': '#8b008b', + 'darkolivegreen': '#556b2f', + 'darkorange': '#ff8c00', + 'darkorchid': '#9932cc', + 'darkred': '#8b0000', + 'darksalmon': '#e9967a', + 'darkseagreen': '#8fbc8f', + 'darkslateblue': '#483d8b', + 'darkslategray': '#2f4f4f', + 'darkturquoise': '#00ced1', + 'darkviolet': '#9400d3', + 'deeppink': '#ff1493', + 'deepskyblue': '#00bfff', + 'dimgray': '#696969', + 'dodgerblue': '#1e90ff', + 'firebrick': '#b22222', + 'floralwhite': '#fffaf0', + 'forestgreen': '#228b22', + 'fuchsia': '#f0f', + 'gainsboro': '#dcdcdc', + 'ghostwhite': '#f8f8ff', + 'gold': '#ffd700', + 'goldenrod': '#daa520', + 'gray': '#808080', + 'green': '#008000', + 'greenyellow': '#adff2f', + 'honeydew': '#f0fff0', + 'hotpink': '#ff69b4', + 'indianred': '#cd5c5c', + 'indigo': '#4b0082', + 'ivory': '#fffff0', + 'khaki': '#f0e68c', + 'lavender': '#e6e6fa', + 'lavenderblush': '#fff0f5', + 'lawngreen': '#7cfc00', + 'lemonchiffon': '#fffacd', + 'lightblue': '#add8e6', + 'lightcoral': '#f08080', + 'lightcyan': '#e0ffff', + 'lightgoldenrodyellow': '#fafad2', + 'lightgreen': '#90ee90', + 'lightgrey': '#d3d3d3', + 'lightpink': '#ffb6c1', + 'lightsalmon': '#ffa07a', + 'lightseagreen': '#20b2aa', + 'lightskyblue': '#87cefa', + 'lightslategray': '#789', + 'lightsteelblue': '#b0c4de', + 'lightyellow': '#ffffe0', + 'lime': '#0f0', + 'limegreen': '#32cd32', + 'linen': '#faf0e6', + 'magenta': '#f0f', + 'maroon': '#800000', + 'mediumaquamarine': '#66cdaa', + 'mediumblue': '#0000cd', + 'mediumorchid': '#ba55d3', + 'mediumpurple': '#9370db', + 'mediumseagreen': '#3cb371', + 'mediumslateblue': '#7b68ee', + 'mediumspringgreen': '#00fa9a', + 'mediumturquoise': '#48d1cc', + 'mediumvioletred': '#c71585', + 'midnightblue': '#191970', + 'mintcream': '#f5fffa', + 'mistyrose': '#ffe4e1', + 'moccasin': '#ffe4b5', + 'navajowhite': '#ffdead', + 'navy': '#000080', + 'oldlace': '#fdf5e6', + 'olive': '#808000', + 'olivedrab': '#6b8e23', + 'orange': '#ffa500', + 'orangered': '#ff4500', + 'orchid': '#da70d6', + 'palegoldenrod': '#eee8aa', + 'palegreen': '#98fb98', + 'paleturquoise': '#afeeee', + 'palevioletred': '#db7093', + 'papayawhip': '#ffefd5', + 'peachpuff': '#ffdab9', + 'peru': '#cd853f', + 'pink': '#ffc0cb', + 'plum': '#dda0dd', + 'powderblue': '#b0e0e6', + 'purple': '#800080', + 'red': '#f00', + 'rosybrown': '#bc8f8f', + 'royalblue': '#4169e1', + 'saddlebrown': '#8b4513', + 'salmon': '#fa8072', + 'sandybrown': '#f4a460', + 'seagreen': '#2e8b57', + 'seashell': '#fff5ee', + 'sienna': '#a0522d', + 'silver': '#c0c0c0', + 'skyblue': '#87ceeb', + 'slateblue': '#6a5acd', + 'slategray': '#708090', + 'snow': '#fffafa', + 'springgreen': '#00ff7f', + 'steelblue': '#4682b4', + 'tan': '#d2b48c', + 'teal': '#008080', + 'thistle': '#d8bfd8', + 'tomato': '#ff6347', + 'turquoise': '#40e0d0', + 'violet': '#ee82ee', + 'wheat': '#f5deb3', + 'white': '#fff', + 'whitesmoke': '#f5f5f5', + 'yellow': '#ff0', + 'yellowgreen': '#9acd32' +}; + +exports.colorsShortNames = { + '#f0ffff': 'azure', + '#f5f5dc': 'beige', + '#ffe4c4': 'bisque', + '#a52a2a': 'brown', + '#ff7f50': 'coral', + '#ffd700': 'gold', + '#808080': 'gray', + '#008000': 'green', + '#4b0082': 'indigo', + '#fffff0': 'ivory', + '#f0e68c': 'khaki', + '#faf0e6': 'linen', + '#800000': 'maroon', + '#000080': 'navy', + '#808000': 'olive', + '#ffa500': 'orange', + '#da70d6': 'orchid', + '#cd853f': 'peru', + '#ffc0cb': 'pink', + '#dda0dd': 'plum', + '#800080': 'purple', + '#f00': 'red', + '#fa8072': 'salmon', + '#a0522d': 'sienna', + '#c0c0c0': 'silver', + '#fffafa': 'snow', + '#d2b48c': 'tan', + '#008080': 'teal', + '#ff6347': 'tomato', + '#ee82ee': 'violet', + '#f5deb3': 'wheat' +}; + +// http://www.w3.org/TR/SVG/single-page.html#types-DataTypeColor +exports.colorsProps = [ + 'color', 'fill', 'stroke', 'stop-color', 'flood-color', 'lighting-color' +]; diff --git a/node_modules/svgo/plugins/_path.js b/node_modules/svgo/plugins/_path.js new file mode 100644 index 00000000..2aa567a0 --- /dev/null +++ b/node_modules/svgo/plugins/_path.js @@ -0,0 +1,962 @@ +/* global a2c */ +'use strict'; + +var regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/, + regPathData = /[-+]?(?:\d*\.\d+|\d+\.?)([eE][-+]?\d+)?/g, + regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/, + transform2js = require('./_transforms').transform2js, + transformsMultiply = require('./_transforms').transformsMultiply, + transformArc = require('./_transforms').transformArc, + collections = require('./_collections.js'), + referencesProps = collections.referencesProps, + defaultStrokeWidth = collections.attrsGroupsDefaults.presentation['stroke-width'], + cleanupOutData = require('../lib/svgo/tools').cleanupOutData, + removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero, + prevCtrlPoint; + +/** + * Convert path string to JS representation. + * + * @param {String} pathString input string + * @param {Object} params plugin params + * @return {Array} output array + */ +exports.path2js = function(path) { + if (path.pathJS) return path.pathJS; + + var paramsLength = { // Number of parameters of every path command + H: 1, V: 1, M: 2, L: 2, T: 2, Q: 4, S: 4, C: 6, A: 7, + h: 1, v: 1, m: 2, l: 2, t: 2, q: 4, s: 4, c: 6, a: 7 + }, + pathData = [], // JS representation of the path data + instruction, // current instruction context + startMoveto = false; + + // splitting path string into array like ['M', '10 50', 'L', '20 30'] + path.attr('d').value.split(regPathInstructions).forEach(function(data) { + if (!data) return; + if (!startMoveto) { + if (data == 'M' || data == 'm') { + startMoveto = true; + } else return; + } + + // instruction item + if (regPathInstructions.test(data)) { + instruction = data; + + // z - instruction w/o data + if (instruction == 'Z' || instruction == 'z') { + pathData.push({ + instruction: 'z' + }); + } + // data item + } else { + data = data.match(regPathData); + if (!data) return; + + data = data.map(Number); + + // Subsequent moveto pairs of coordinates are threated as implicit lineto commands + // http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands + if (instruction == 'M' || instruction == 'm') { + pathData.push({ + instruction: pathData.length == 0 ? 'M' : instruction, + data: data.splice(0, 2) + }); + instruction = instruction == 'M' ? 'L' : 'l'; + } + + for (var pair = paramsLength[instruction]; data.length;) { + pathData.push({ + instruction: instruction, + data: data.splice(0, pair) + }); + } + } + }); + + // First moveto is actually absolute. Subsequent coordinates were separated above. + if (pathData.length && pathData[0].instruction == 'm') { + pathData[0].instruction = 'M'; + } + path.pathJS = pathData; + + return pathData; +}; + +/** + * Convert relative Path data to absolute. + * + * @param {Array} data input data + * @return {Array} output data + */ +var relative2absolute = exports.relative2absolute = function(data) { + var currentPoint = [0, 0], + subpathPoint = [0, 0], + i; + + data = data.map(function(item) { + + var instruction = item.instruction, + itemData = item.data && item.data.slice(); + + if (instruction == 'M') { + + set(currentPoint, itemData); + set(subpathPoint, itemData); + + } else if ('mlcsqt'.indexOf(instruction) > -1) { + + for (i = 0; i < itemData.length; i++) { + itemData[i] += currentPoint[i % 2]; + } + set(currentPoint, itemData); + + if (instruction == 'm') { + set(subpathPoint, itemData); + } + + } else if (instruction == 'a') { + + itemData[5] += currentPoint[0]; + itemData[6] += currentPoint[1]; + set(currentPoint, itemData); + + } else if (instruction == 'h') { + + itemData[0] += currentPoint[0]; + currentPoint[0] = itemData[0]; + + } else if (instruction == 'v') { + + itemData[0] += currentPoint[1]; + currentPoint[1] = itemData[0]; + + } else if ('MZLCSQTA'.indexOf(instruction) > -1) { + + set(currentPoint, itemData); + + } else if (instruction == 'H') { + + currentPoint[0] = itemData[0]; + + } else if (instruction == 'V') { + + currentPoint[1] = itemData[0]; + + } else if (instruction == 'z') { + + set(currentPoint, subpathPoint); + + } + + return instruction == 'z' ? + { instruction: 'z' } : + { + instruction: instruction.toUpperCase(), + data: itemData + }; + + }); + + return data; +}; + +/** + * Apply transformation(s) to the Path data. + * + * @param {Object} elem current element + * @param {Array} path input path data + * @param {Object} params whether to apply transforms to stroked lines and transform precision (used for stroke width) + * @return {Array} output path data + */ +exports.applyTransforms = function(elem, path, params) { + // if there are no 'stroke' attr and references to other objects such as + // gradiends or clip-path which are also subjects to transform. + if (!elem.hasAttr('transform') || !elem.attr('transform').value || + elem.someAttr(function(attr) { + return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url('); + })) + return path; + + var matrix = transformsMultiply(transform2js(elem.attr('transform').value)), + stroke = elem.computedAttr('stroke'), + id = elem.computedAttr('id'), + transformPrecision = params.transformPrecision, + newPoint, scale; + + if (stroke && stroke != 'none') { + if (!params.applyTransformsStroked || + (matrix.data[0] != matrix.data[3] || matrix.data[1] != -matrix.data[2]) && + (matrix.data[0] != -matrix.data[3] || matrix.data[1] != matrix.data[2])) + return path; + + // "stroke-width" should be inside the part with ID, otherwise it can be overrided in <use> + if (id) { + var idElem = elem, + hasStrokeWidth = false; + + do { + if (idElem.hasAttr('stroke-width')) hasStrokeWidth = true; + } while (!idElem.hasAttr('id', id) && !hasStrokeWidth && (idElem = idElem.parentNode)); + + if (!hasStrokeWidth) return path; + } + + scale = +Math.sqrt(matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]).toFixed(transformPrecision); + + if (scale !== 1) { + var strokeWidth = elem.computedAttr('stroke-width') || defaultStrokeWidth; + + if (elem.hasAttr('stroke-width')) { + elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value.trim() + .replace(regNumericValues, function(num) { return removeLeadingZero(num * scale) }); + } else { + elem.addAttr({ + name: 'stroke-width', + prefix: '', + local: 'stroke-width', + value: strokeWidth.replace(regNumericValues, function(num) { return removeLeadingZero(num * scale) }) + }); + } + } + } else if (id) { // Stroke and stroke-width can be redefined with <use> + return path; + } + + path.forEach(function(pathItem) { + + if (pathItem.data) { + + // h -> l + if (pathItem.instruction === 'h') { + + pathItem.instruction = 'l'; + pathItem.data[1] = 0; + + // v -> l + } else if (pathItem.instruction === 'v') { + + pathItem.instruction = 'l'; + pathItem.data[1] = pathItem.data[0]; + pathItem.data[0] = 0; + + } + + // if there is a translate() transform + if (pathItem.instruction === 'M' && + (matrix.data[4] !== 0 || + matrix.data[5] !== 0) + ) { + + // then apply it only to the first absoluted M + newPoint = transformPoint(matrix.data, pathItem.data[0], pathItem.data[1]); + set(pathItem.data, newPoint); + set(pathItem.coords, newPoint); + + // clear translate() data from transform matrix + matrix.data[4] = 0; + matrix.data[5] = 0; + + } else { + + if (pathItem.instruction == 'a') { + + transformArc(pathItem.data, matrix.data); + + // reduce number of digits in rotation angle + if (Math.abs(pathItem.data[2]) > 80) { + var a = pathItem.data[0], + rotation = pathItem.data[2]; + pathItem.data[0] = pathItem.data[1]; + pathItem.data[1] = a; + pathItem.data[2] = rotation + (rotation > 0 ? -90 : 90); + } + + newPoint = transformPoint(matrix.data, pathItem.data[5], pathItem.data[6]); + pathItem.data[5] = newPoint[0]; + pathItem.data[6] = newPoint[1]; + + } else { + + for (var i = 0; i < pathItem.data.length; i += 2) { + newPoint = transformPoint(matrix.data, pathItem.data[i], pathItem.data[i + 1]); + pathItem.data[i] = newPoint[0]; + pathItem.data[i + 1] = newPoint[1]; + } + } + + pathItem.coords[0] = pathItem.base[0] + pathItem.data[pathItem.data.length - 2]; + pathItem.coords[1] = pathItem.base[1] + pathItem.data[pathItem.data.length - 1]; + + } + + } + + }); + + // remove transform attr + elem.removeAttr('transform'); + + return path; +}; + +/** + * Apply transform 3x3 matrix to x-y point. + * + * @param {Array} matrix transform 3x3 matrix + * @param {Array} point x-y point + * @return {Array} point with new coordinates + */ +function transformPoint(matrix, x, y) { + + return [ + matrix[0] * x + matrix[2] * y + matrix[4], + matrix[1] * x + matrix[3] * y + matrix[5] + ]; + +} + +/** + * Compute Cubic Bézie bounding box. + * + * @see http://processingjs.nihongoresources.com/bezierinfo/ + * + * @param {Float} xa + * @param {Float} ya + * @param {Float} xb + * @param {Float} yb + * @param {Float} xc + * @param {Float} yc + * @param {Float} xd + * @param {Float} yd + * + * @return {Object} + */ +exports.computeCubicBoundingBox = function(xa, ya, xb, yb, xc, yc, xd, yd) { + + var minx = Number.POSITIVE_INFINITY, + miny = Number.POSITIVE_INFINITY, + maxx = Number.NEGATIVE_INFINITY, + maxy = Number.NEGATIVE_INFINITY, + ts, + t, + x, + y, + i; + + // X + if (xa < minx) { minx = xa; } + if (xa > maxx) { maxx = xa; } + if (xd < minx) { minx= xd; } + if (xd > maxx) { maxx = xd; } + + ts = computeCubicFirstDerivativeRoots(xa, xb, xc, xd); + + for (i = 0; i < ts.length; i++) { + + t = ts[i]; + + if (t >= 0 && t <= 1) { + x = computeCubicBaseValue(t, xa, xb, xc, xd); + // y = computeCubicBaseValue(t, ya, yb, yc, yd); + + if (x < minx) { minx = x; } + if (x > maxx) { maxx = x; } + } + + } + + // Y + if (ya < miny) { miny = ya; } + if (ya > maxy) { maxy = ya; } + if (yd < miny) { miny = yd; } + if (yd > maxy) { maxy = yd; } + + ts = computeCubicFirstDerivativeRoots(ya, yb, yc, yd); + + for (i = 0; i < ts.length; i++) { + + t = ts[i]; + + if (t >= 0 && t <= 1) { + // x = computeCubicBaseValue(t, xa, xb, xc, xd); + y = computeCubicBaseValue(t, ya, yb, yc, yd); + + if (y < miny) { miny = y; } + if (y > maxy) { maxy = y; } + } + + } + + return { + minx: minx, + miny: miny, + maxx: maxx, + maxy: maxy + }; + +}; + +// compute the value for the cubic bezier function at time=t +function computeCubicBaseValue(t, a, b, c, d) { + + var mt = 1 - t; + + return mt * mt * mt * a + 3 * mt * mt * t * b + 3 * mt * t * t * c + t * t * t * d; + +} + +// compute the value for the first derivative of the cubic bezier function at time=t +function computeCubicFirstDerivativeRoots(a, b, c, d) { + + var result = [-1, -1], + tl = -a + 2 * b - c, + tr = -Math.sqrt(-a * (c - d) + b * b - b * (c + d) + c * c), + dn = -a + 3 * b - 3 * c + d; + + if (dn !== 0) { + result[0] = (tl + tr) / dn; + result[1] = (tl - tr) / dn; + } + + return result; + +} + +/** + * Compute Quadratic Bézier bounding box. + * + * @see http://processingjs.nihongoresources.com/bezierinfo/ + * + * @param {Float} xa + * @param {Float} ya + * @param {Float} xb + * @param {Float} yb + * @param {Float} xc + * @param {Float} yc + * + * @return {Object} + */ +exports.computeQuadraticBoundingBox = function(xa, ya, xb, yb, xc, yc) { + + var minx = Number.POSITIVE_INFINITY, + miny = Number.POSITIVE_INFINITY, + maxx = Number.NEGATIVE_INFINITY, + maxy = Number.NEGATIVE_INFINITY, + t, + x, + y; + + // X + if (xa < minx) { minx = xa; } + if (xa > maxx) { maxx = xa; } + if (xc < minx) { minx = xc; } + if (xc > maxx) { maxx = xc; } + + t = computeQuadraticFirstDerivativeRoot(xa, xb, xc); + + if (t >= 0 && t <= 1) { + x = computeQuadraticBaseValue(t, xa, xb, xc); + // y = computeQuadraticBaseValue(t, ya, yb, yc); + + if (x < minx) { minx = x; } + if (x > maxx) { maxx = x; } + } + + // Y + if (ya < miny) { miny = ya; } + if (ya > maxy) { maxy = ya; } + if (yc < miny) { miny = yc; } + if (yc > maxy) { maxy = yc; } + + t = computeQuadraticFirstDerivativeRoot(ya, yb, yc); + + if (t >= 0 && t <=1 ) { + // x = computeQuadraticBaseValue(t, xa, xb, xc); + y = computeQuadraticBaseValue(t, ya, yb, yc); + + if (y < miny) { miny = y; } + if (y > maxy) { maxy = y ; } + + } + + return { + minx: minx, + miny: miny, + maxx: maxx, + maxy: maxy + }; + +}; + +// compute the value for the quadratic bezier function at time=t +function computeQuadraticBaseValue(t, a, b, c) { + + var mt = 1 - t; + + return mt * mt * a + 2 * mt * t * b + t * t * c; + +} + +// compute the value for the first derivative of the quadratic bezier function at time=t +function computeQuadraticFirstDerivativeRoot(a, b, c) { + + var t = -1, + denominator = a - 2 * b + c; + + if (denominator !== 0) { + t = (a - b) / denominator; + } + + return t; + +} + +/** + * Convert path array to string. + * + * @param {Array} path input path data + * @param {Object} params plugin params + * @return {String} output path string + */ +exports.js2path = function(path, data, params) { + + path.pathJS = data; + + if (params.collapseRepeated) { + data = collapseRepeated(data); + } + + path.attr('d').value = data.reduce(function(pathString, item) { + return pathString += item.instruction + (item.data ? cleanupOutData(item.data, params) : ''); + }, ''); + +}; + +/** + * Collapse repeated instructions data + * + * @param {Array} path input path data + * @return {Array} output path data + */ +function collapseRepeated(data) { + + var prev, + prevIndex; + + // copy an array and modifieds item to keep original data untouched + data = data.reduce(function(newPath, item) { + if ( + prev && item.data && + item.instruction == prev.instruction + ) { + // concat previous data with current + if (item.instruction != 'M') { + prev = newPath[prevIndex] = { + instruction: prev.instruction, + data: prev.data.concat(item.data), + coords: item.coords, + base: prev.base + }; + } else { + prev.data = item.data; + prev.coords = item.coords; + } + } else { + newPath.push(item); + prev = item; + prevIndex = newPath.length - 1; + } + + return newPath; + }, []); + + return data; + +} + +function set(dest, source) { + dest[0] = source[source.length - 2]; + dest[1] = source[source.length - 1]; + return dest; +} + +/** + * Checks if two paths have an intersection by checking convex hulls + * collision using Gilbert-Johnson-Keerthi distance algorithm + * http://entropyinteractive.com/2011/04/gjk-algorithm/ + * + * @param {Array} path1 JS path representation + * @param {Array} path2 JS path representation + * @return {Boolean} + */ +exports.intersects = function(path1, path2) { + if (path1.length < 3 || path2.length < 3) return false; // nothing to fill + + // Collect points of every subpath. + var points1 = relative2absolute(path1).reduce(gatherPoints, []), + points2 = relative2absolute(path2).reduce(gatherPoints, []); + + // Axis-aligned bounding box check. + if (points1.maxX <= points2.minX || points2.maxX <= points1.minX || + points1.maxY <= points2.minY || points2.maxY <= points1.minY || + points1.every(function (set1) { + return points2.every(function (set2) { + return set1[set1.maxX][0] <= set2[set2.minX][0] || + set2[set2.maxX][0] <= set1[set1.minX][0] || + set1[set1.maxY][1] <= set2[set2.minY][1] || + set2[set2.maxY][1] <= set1[set1.minY][1]; + }); + }) + ) return false; + + // Get a convex hull from points of each subpath. Has the most complexity O(n·log n). + var hullNest1 = points1.map(convexHull), + hullNest2 = points2.map(convexHull); + + // Check intersection of every subpath of the first path with every subpath of the second. + return hullNest1.some(function(hull1) { + if (hull1.length < 3) return false; + + return hullNest2.some(function(hull2) { + if (hull2.length < 3) return false; + + var simplex = [getSupport(hull1, hull2, [1, 0])], // create the initial simplex + direction = minus(simplex[0]); // set the direction to point towards the origin + + var iterations = 1e4; // infinite loop protection, 10 000 iterations is more than enough + while (true) { + if (iterations-- == 0) { + console.error('Error: infinite loop while processing mergePaths plugin.'); + return true; // true is the safe value that means “do nothing with paths” + } + // add a new point + simplex.push(getSupport(hull1, hull2, direction)); + // see if the new point was on the correct side of the origin + if (dot(direction, simplex[simplex.length - 1]) <= 0) return false; + // process the simplex + if (processSimplex(simplex, direction)) return true; + } + }); + }); + + function getSupport(a, b, direction) { + return sub(supportPoint(a, direction), supportPoint(b, minus(direction))); + } + + // Computes farthest polygon point in particular direction. + // Thanks to knowledge of min/max x and y coordinates we can choose a quadrant to search in. + // Since we're working on convex hull, the dot product is increasing until we find the farthest point. + function supportPoint(polygon, direction) { + var index = direction[1] >= 0 ? + direction[0] < 0 ? polygon.maxY : polygon.maxX : + direction[0] < 0 ? polygon.minX : polygon.minY, + max = -Infinity, + value; + while ((value = dot(polygon[index], direction)) > max) { + max = value; + index = ++index % polygon.length; + } + return polygon[(index || polygon.length) - 1]; + } +}; + +function processSimplex(simplex, direction) { + /* jshint -W004 */ + + // we only need to handle to 1-simplex and 2-simplex + if (simplex.length == 2) { // 1-simplex + var a = simplex[1], + b = simplex[0], + AO = minus(simplex[1]), + AB = sub(b, a); + // AO is in the same direction as AB + if (dot(AO, AB) > 0) { + // get the vector perpendicular to AB facing O + set(direction, orth(AB, a)); + } else { + set(direction, AO); + // only A remains in the simplex + simplex.shift(); + } + } else { // 2-simplex + var a = simplex[2], // [a, b, c] = simplex + b = simplex[1], + c = simplex[0], + AB = sub(b, a), + AC = sub(c, a), + AO = minus(a), + ACB = orth(AB, AC), // the vector perpendicular to AB facing away from C + ABC = orth(AC, AB); // the vector perpendicular to AC facing away from B + + if (dot(ACB, AO) > 0) { + if (dot(AB, AO) > 0) { // region 4 + set(direction, ACB); + simplex.shift(); // simplex = [b, a] + } else { // region 5 + set(direction, AO); + simplex.splice(0, 2); // simplex = [a] + } + } else if (dot(ABC, AO) > 0) { + if (dot(AC, AO) > 0) { // region 6 + set(direction, ABC); + simplex.splice(1, 1); // simplex = [c, a] + } else { // region 5 (again) + set(direction, AO); + simplex.splice(0, 2); // simplex = [a] + } + } else // region 7 + return true; + } + return false; +} + +function minus(v) { + return [-v[0], -v[1]]; +} + +function sub(v1, v2) { + return [v1[0] - v2[0], v1[1] - v2[1]]; +} + +function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} + +function orth(v, from) { + var o = [-v[1], v[0]]; + return dot(o, minus(from)) < 0 ? minus(o) : o; +} + +function gatherPoints(points, item, index, path) { + + var subPath = points.length && points[points.length - 1], + prev = index && path[index - 1], + basePoint = subPath.length && subPath[subPath.length - 1], + data = item.data, + ctrlPoint = basePoint; + + switch (item.instruction) { + case 'M': + points.push(subPath = []); + break; + case 'H': + addPoint(subPath, [data[0], basePoint[1]]); + break; + case 'V': + addPoint(subPath, [basePoint[0], data[0]]); + break; + case 'Q': + addPoint(subPath, data.slice(0, 2)); + prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; // Save control point for shorthand + break; + case 'T': + if (prev.instruction == 'Q' && prev.instruction == 'T') { + ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]]; + addPoint(subPath, ctrlPoint); + prevCtrlPoint = [data[0] - ctrlPoint[0], data[1] - ctrlPoint[1]]; + } + break; + case 'C': + // Approximate quibic Bezier curve with middle points between control points + addPoint(subPath, [.5 * (basePoint[0] + data[0]), .5 * (basePoint[1] + data[1])]); + addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]); + addPoint(subPath, [.5 * (data[2] + data[4]), .5 * (data[3] + data[5])]); + prevCtrlPoint = [data[4] - data[2], data[5] - data[3]]; // Save control point for shorthand + break; + case 'S': + if (prev.instruction == 'C' && prev.instruction == 'S') { + addPoint(subPath, [basePoint[0] + .5 * prevCtrlPoint[0], basePoint[1] + .5 * prevCtrlPoint[1]]); + ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]]; + } + addPoint(subPath, [.5 * (ctrlPoint[0] + data[0]), .5 * (ctrlPoint[1]+ data[1])]); + addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]); + prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; + break; + case 'A': + // Convert the arc to bezier curves and use the same approximation + var curves = a2c.apply(0, basePoint.concat(data)); + for (var cData; (cData = curves.splice(0,6).map(toAbsolute)).length;) { + addPoint(subPath, [.5 * (basePoint[0] + cData[0]), .5 * (basePoint[1] + cData[1])]); + addPoint(subPath, [.5 * (cData[0] + cData[2]), .5 * (cData[1] + cData[3])]); + addPoint(subPath, [.5 * (cData[2] + cData[4]), .5 * (cData[3] + cData[5])]); + if (curves.length) addPoint(subPath, basePoint = cData.slice(-2)); + } + break; + } + // Save final command coordinates + if (data && data.length >= 2) addPoint(subPath, data.slice(-2)); + return points; + + function toAbsolute(n, i) { return n + basePoint[i % 2] } + + // Writes data about the extreme points on each axle + function addPoint(path, point) { + if (!path.length || point[1] > path[path.maxY][1]) { + path.maxY = path.length; + points.maxY = points.length ? Math.max(point[1], points.maxY) : point[1]; + } + if (!path.length || point[0] > path[path.maxX][0]) { + path.maxX = path.length; + points.maxX = points.length ? Math.max(point[0], points.maxX) : point[0]; + } + if (!path.length || point[1] < path[path.minY][1]) { + path.minY = path.length; + points.minY = points.length ? Math.min(point[1], points.minY) : point[1]; + } + if (!path.length || point[0] < path[path.minX][0]) { + path.minX = path.length; + points.minX = points.length ? Math.min(point[0], points.minX) : point[0]; + } + path.push(point); + } +} + +/** + * Forms a convex hull from set of points of every subpath using monotone chain convex hull algorithm. + * http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain + * + * @param points An array of [X, Y] coordinates + */ +function convexHull(points) { + /* jshint -W004 */ + + points.sort(function(a, b) { + return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]; + }); + + var lower = [], + minY = 0, + bottom = 0; + for (var i = 0; i < points.length; i++) { + while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) { + lower.pop(); + } + if (points[i][1] < points[minY][1]) { + minY = i; + bottom = lower.length; + } + lower.push(points[i]); + } + + var upper = [], + maxY = points.length - 1, + top = 0; + for (var i = points.length; i--;) { + while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) { + upper.pop(); + } + if (points[i][1] > points[maxY][1]) { + maxY = i; + top = upper.length; + } + upper.push(points[i]); + } + + // last points are equal to starting points of the other part + upper.pop(); + lower.pop(); + + var hull = lower.concat(upper); + + hull.minX = 0; // by sorting + hull.maxX = lower.length; + hull.minY = bottom; + hull.maxY = (lower.length + top) % hull.length; + + return hull; +} + +function cross(o, a, b) { + return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); +} + +/* Based on code from Snap.svg (Apache 2 license). http://snapsvg.io/ + * Thanks to Dmitry Baranovskiy for his great work! + */ + +// jshint ignore: start +function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this Math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = Math.PI * 120 / 180, + rad = Math.PI / 180 * (+angle || 0), + res = [], + rotateX = function(x, y, rad) { return x * Math.cos(rad) - y * Math.sin(rad) }, + rotateY = function(x, y, rad) { return x * Math.sin(rad) + y * Math.cos(rad) }; + if (!recursive) { + x1 = rotateX(x1, y1, -rad); + y1 = rotateY(x1, y1, -rad); + x2 = rotateX(x2, y2, -rad); + y2 = rotateY(x2, y2, -rad); + var x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = Math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = Math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = Math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? Math.PI - f1 : f1; + f2 = x2 < cx ? Math.PI - f2 : f2; + f1 < 0 && (f1 = Math.PI * 2 + f1); + f2 < 0 && (f2 = Math.PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - Math.PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - Math.PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (Math.abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * Math.cos(f2); + y2 = cy + ry * Math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = Math.cos(f1), + s1 = Math.sin(f1), + c2 = Math.cos(f2), + s2 = Math.sin(f2), + t = Math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m = [ + - hx * s1, hy * c1, + x2 + hx * s2 - x1, y2 - hy * c2 - y1, + x2 - x1, y2 - y1 + ]; + if (recursive) { + return m.concat(res); + } else { + res = m.concat(res); + var newres = []; + for (var i = 0, n = res.length; i < n; i++) { + newres[i] = i % 2 ? rotateY(res[i - 1], res[i], rad) : rotateX(res[i], res[i + 1], rad); + } + return newres; + } +} +// jshint ignore: end diff --git a/node_modules/svgo/plugins/_transforms.js b/node_modules/svgo/plugins/_transforms.js new file mode 100644 index 00000000..796ca259 --- /dev/null +++ b/node_modules/svgo/plugins/_transforms.js @@ -0,0 +1,308 @@ +'use strict'; + +var regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/, + regTransformSplit = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/, + regNumericValues = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; + +/** + * Convert transform string to JS representation. + * + * @param {String} transformString input string + * @param {Object} params plugin params + * @return {Array} output array + */ +exports.transform2js = function(transformString) { + + // JS representation of the transform data + var transforms = [], + // current transform context + current; + + // split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', ''] + transformString.split(regTransformSplit).forEach(function(item) { + /*jshint -W084 */ + var num; + + if (item) { + // if item is a translate function + if (regTransformTypes.test(item)) { + // then collect it and change current context + transforms.push(current = { name: item }); + // else if item is data + } else { + // then split it into [10, 50] and collect as context.data + while (num = regNumericValues.exec(item)) { + num = Number(num); + if (current.data) + current.data.push(num); + else + current.data = [num]; + } + } + } + }); + + return transforms; + +}; + +/** + * Multiply transforms into one. + * + * @param {Array} input transforms array + * @return {Array} output matrix array + */ +exports.transformsMultiply = function(transforms) { + + // convert transforms objects to the matrices + transforms = transforms.map(function(transform) { + if (transform.name === 'matrix') { + return transform.data; + } + return transformToMatrix(transform); + }); + + // multiply all matrices into one + transforms = { + name: 'matrix', + data: transforms.reduce(function(a, b) { + return multiplyTransformMatrices(a, b); + }) + }; + + return transforms; + +}; + +/** + * Do math like a schoolgirl. + * + * @type {Object} + */ +var mth = exports.mth = { + + rad: function(deg) { + return deg * Math.PI / 180; + }, + + deg: function(rad) { + return rad * 180 / Math.PI; + }, + + cos: function(deg) { + return Math.cos(this.rad(deg)); + }, + + acos: function(val, floatPrecision) { + return +(this.deg(Math.acos(val)).toFixed(floatPrecision)); + }, + + sin: function(deg) { + return Math.sin(this.rad(deg)); + }, + + asin: function(val, floatPrecision) { + return +(this.deg(Math.asin(val)).toFixed(floatPrecision)); + }, + + tan: function(deg) { + return Math.tan(this.rad(deg)); + }, + + atan: function(val, floatPrecision) { + return +(this.deg(Math.atan(val)).toFixed(floatPrecision)); + } + +}; + +/** + * Decompose matrix into simple transforms. See + * http://www.maths-informatique-jeux.com/blog/frederic/?post/2013/12/01/Decomposition-of-2D-transform-matrices + * + * @param {Object} data matrix transform object + * @return {Object|Array} transforms array or original transform object + */ +exports.matrixToTransform = function(transform, params) { + var floatPrecision = params.floatPrecision, + data = transform.data, + transforms = [], + sx = +Math.sqrt(data[0] * data[0] + data[1] * data[1]).toFixed(params.transformPrecision), + sy = +((data[0] * data[3] - data[1] * data[2]) / sx).toFixed(params.transformPrecision), + colsSum = data[0] * data[2] + data[1] * data[3], + rowsSum = data[0] * data[1] + data[2] * data[3], + scaleBefore = rowsSum || +(sx == sy); + + // [..., ..., ..., ..., tx, ty] → translate(tx, ty) + if (data[4] || data[5]) { + transforms.push({ name: 'translate', data: data.slice(4, data[5] ? 6 : 5) }); + } + + // [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy) + if (!data[1] && data[2]) { + transforms.push({ name: 'skewX', data: [mth.atan(data[2] / sy, floatPrecision)] }); + + // [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy) + } else if (data[1] && !data[2]) { + transforms.push({ name: 'skewY', data: [mth.atan(data[1] / data[0], floatPrecision)] }); + sx = data[0]; + sy = data[3]; + + // [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or + // [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore) + } else if (!colsSum || (sx == 1 && sy == 1) || !scaleBefore) { + if (!scaleBefore) { + sx = (data[0] < 0 ? -1 : 1) * Math.sqrt(data[0] * data[0] + data[2] * data[2]); + sy = (data[3] < 0 ? -1 : 1) * Math.sqrt(data[1] * data[1] + data[3] * data[3]); + transforms.push({ name: 'scale', data: [sx, sy] }); + } + var rotate = [mth.acos(data[0] / sx, floatPrecision) * (data[1] * sy < 0 ? -1 : 1)]; + + if (rotate[0]) transforms.push({ name: 'rotate', data: rotate }); + + if (rowsSum && colsSum) transforms.push({ + name: 'skewX', + data: [mth.atan(colsSum / (sx * sx), floatPrecision)] + }); + + // rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point) + if (rotate[0] && (data[4] || data[5])) { + transforms.shift(); + var cos = data[0] / sx, + sin = data[1] / (scaleBefore ? sx : sy), + x = data[4] * (scaleBefore || sy), + y = data[5] * (scaleBefore || sx), + denom = (Math.pow(1 - cos, 2) + Math.pow(sin, 2)) * (scaleBefore || sx * sy); + rotate.push(((1 - cos) * x - sin * y) / denom); + rotate.push(((1 - cos) * y + sin * x) / denom); + } + + // Too many transformations, return original matrix if it isn't just a scale/translate + } else if (data[1] || data[2]) { + return transform; + } + + if (scaleBefore && (sx != 1 || sy != 1) || !transforms.length) transforms.push({ + name: 'scale', + data: sx == sy ? [sx] : [sx, sy] + }); + + return transforms; +}; + +/** + * Convert transform to the matrix data. + * + * @param {Object} transform transform object + * @return {Array} matrix data + */ +function transformToMatrix(transform) { + + if (transform.name === 'matrix') return transform.data; + + var matrix; + + switch (transform.name) { + case 'translate': + // [1, 0, 0, 1, tx, ty] + matrix = [1, 0, 0, 1, transform.data[0], transform.data[1] || 0]; + break; + case 'scale': + // [sx, 0, 0, sy, 0, 0] + matrix = [transform.data[0], 0, 0, transform.data[1] || transform.data[0], 0, 0]; + break; + case 'rotate': + // [cos(a), sin(a), -sin(a), cos(a), x, y] + var cos = mth.cos(transform.data[0]), + sin = mth.sin(transform.data[0]), + cx = transform.data[1] || 0, + cy = transform.data[2] || 0; + + matrix = [cos, sin, -sin, cos, (1 - cos) * cx + sin * cy, (1 - cos) * cy - sin * cx]; + break; + case 'skewX': + // [1, 0, tan(a), 1, 0, 0] + matrix = [1, 0, mth.tan(transform.data[0]), 1, 0, 0]; + break; + case 'skewY': + // [1, tan(a), 0, 1, 0, 0] + matrix = [1, mth.tan(transform.data[0]), 0, 1, 0, 0]; + break; + } + + return matrix; + +} + +/** + * Applies transformation to an arc. To do so, we represent ellipse as a matrix, multiply it + * by the transformation matrix and use a singular value decomposition to represent in a form + * rotate(θ)·scale(a b)·rotate(φ). This gives us new ellipse params a, b and θ. + * SVD is being done with the formulae provided by Wolffram|Alpha (svd {{m0, m2}, {m1, m3}}) + * + * @param {Array} arc [a, b, rotation in deg] + * @param {Array} transform transformation matrix + * @return {Array} arc transformed input arc + */ +exports.transformArc = function(arc, transform) { + + var a = arc[0], + b = arc[1], + rot = arc[2] * Math.PI / 180, + cos = Math.cos(rot), + sin = Math.sin(rot), + h = Math.pow(arc[5] * cos + arc[6] * sin, 2) / (4 * a * a) + + Math.pow(arc[6] * cos - arc[5] * sin, 2) / (4 * b * b); + if (h > 1) { + h = Math.sqrt(h); + a *= h; + b *= h; + } + var ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0], + m = multiplyTransformMatrices(transform, ellipse), + // Decompose the new ellipse matrix + lastCol = m[2] * m[2] + m[3] * m[3], + squareSum = m[0] * m[0] + m[1] * m[1] + lastCol, + root = Math.sqrt( + (Math.pow(m[0] - m[3], 2) + Math.pow(m[1] + m[2], 2)) * + (Math.pow(m[0] + m[3], 2) + Math.pow(m[1] - m[2], 2)) + ); + + if (!root) { // circle + arc[0] = arc[1] = Math.sqrt(squareSum / 2); + arc[2] = 0; + } else { + var majorAxisSqr = (squareSum + root) / 2, + minorAxisSqr = (squareSum - root) / 2, + major = Math.abs(majorAxisSqr - lastCol) > 1e-6, + sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol, + rowsSum = m[0] * m[2] + m[1] * m[3], + term1 = m[0] * sub + m[2] * rowsSum, + term2 = m[1] * sub + m[3] * rowsSum; + arc[0] = Math.sqrt(majorAxisSqr); + arc[1] = Math.sqrt(minorAxisSqr); + arc[2] = ((major ? term2 < 0 : term1 > 0) ? -1 : 1) * + Math.acos((major ? term1 : term2) / Math.sqrt(term1 * term1 + term2 * term2)) * 180 / Math.PI; + } + return arc; + +}; + +/** + * Multiply transformation matrices. + * + * @param {Array} a matrix A data + * @param {Array} b matrix B data + * @return {Array} result + */ +function multiplyTransformMatrices(a, b) { + + return [ + a[0] * b[0] + a[2] * b[1], + a[1] * b[0] + a[3] * b[1], + a[0] * b[2] + a[2] * b[3], + a[1] * b[2] + a[3] * b[3], + a[0] * b[4] + a[2] * b[5] + a[4], + a[1] * b[4] + a[3] * b[5] + a[5] + ]; + +} diff --git a/node_modules/svgo/plugins/addAttributesToSVGElement.js b/node_modules/svgo/plugins/addAttributesToSVGElement.js new file mode 100644 index 00000000..9b97c95c --- /dev/null +++ b/node_modules/svgo/plugins/addAttributesToSVGElement.js @@ -0,0 +1,57 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = false; + +exports.description = 'adds attributes to an outer <svg> element'; + +var ENOCLS = 'Error in plugin "addAttributesToSVGElement": absent parameters.\n\ +It should have a list of classes in "attributes" or one "attribute".\n\ +Config example:\n\n\ +\ +plugins:\n\ +- addAttributesToSVGElement:\n\ + attribute: "mySvg"\n\n\ +\ +plugins:\n\ +- addAttributesToSVGElement:\n\ + attributes: ["mySvg", "size-big"]\n'; + +/** + * Add attributes to an outer <svg> element. Example config: + * + * plugins: + * - addAttributesToSVGElement: + * attribute: 'data-icon' + * + * plugins: + * - addAttributesToSVGElement: + * attributes: ['data-icon', 'data-disabled'] + * + * @author April Arcus + */ +exports.fn = function(data, params) { + if (!params || !(Array.isArray(params.attributes) && params.attributes.some(String) || params.attribute)) { + console.error(ENOCLS); + return data; + } + + var attributes = params.attributes || [ params.attribute ], + svg = data.content[0]; + + if (svg.isElem('svg')) { + attributes.forEach(function (attribute) { + if (!svg.hasAttr(attribute)) { + svg.addAttr({ + name: attribute, + prefix: '', + local: attribute + }); + } + }); + } + + return data; + +}; diff --git a/node_modules/svgo/plugins/addClassesToSVGElement.js b/node_modules/svgo/plugins/addClassesToSVGElement.js new file mode 100644 index 00000000..3f9596aa --- /dev/null +++ b/node_modules/svgo/plugins/addClassesToSVGElement.js @@ -0,0 +1,64 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = false; + +exports.description = 'adds classnames to an outer <svg> element'; + +var ENOCLS = 'Error in plugin "addClassesToSVGElement": absent parameters.\n\ +It should have a list of classes in "classNames" or one "className".\n\ +Config example:\n\n\ +\ +plugins:\n\ +- addClassesToSVGElement:\n\ + className: "mySvg"\n\n\ +\ +plugins:\n\ +- addClassesToSVGElement:\n\ + classNames: ["mySvg", "size-big"]\n'; + +/** + * Add classnames to an outer <svg> element. Example config: + * + * plugins: + * - addClassesToSVGElement: + * className: 'mySvg' + * + * plugins: + * - addClassesToSVGElement: + * classNames: ['mySvg', 'size-big'] + * + * @author April Arcus + */ +exports.fn = function(data, params) { + if (!params || !(Array.isArray(params.classNames) && params.classNames.some(String) || params.className)) { + console.error(ENOCLS); + return data; + } + + var classNames = params.classNames || [ params.className ], + svg = data.content[0]; + + if (svg.isElem('svg')) { + if (svg.hasAttr('class')) { + var classes = svg.attr('class').value.split(' '); + classNames.forEach(function(className){ + if (classes.indexOf(className) < 0) { + classes.push(className); + } + }); + svg.attr('class').value = classes.join(' '); + } else { + svg.addAttr({ + name: 'class', + value: classNames.join(' '), + prefix: '', + local: 'class' + }); + } + } + + return data; + +}; diff --git a/node_modules/svgo/plugins/cleanupAttrs.js b/node_modules/svgo/plugins/cleanupAttrs.js new file mode 100644 index 00000000..47e77ac7 --- /dev/null +++ b/node_modules/svgo/plugins/cleanupAttrs.js @@ -0,0 +1,56 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'cleanups attributes from newlines, trailing and repeating spaces'; + +exports.params = { + newlines: true, + trim: true, + spaces: true +}; + +var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g, + regNewlines = /\r?\n/g, + regSpaces = /\s{2,}/g; + +/** + * Cleanup attributes values from newlines, trailing and repeating spaces. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem()) { + + item.eachAttr(function(attr) { + + if (params.newlines) { + // new line which requires a space instead of themselve + attr.value = attr.value.replace(regNewlinesNeedSpace, function(match, p1, p2) { + return p1 + ' ' + p2; + }); + + // simple new line + attr.value = attr.value.replace(regNewlines, ''); + } + + if (params.trim) { + attr.value = attr.value.trim(); + } + + if (params.spaces) { + attr.value = attr.value.replace(regSpaces, ' '); + } + + }); + + } + +}; diff --git a/node_modules/svgo/plugins/cleanupEnableBackground.js b/node_modules/svgo/plugins/cleanupEnableBackground.js new file mode 100644 index 00000000..e6384ab5 --- /dev/null +++ b/node_modules/svgo/plugins/cleanupEnableBackground.js @@ -0,0 +1,84 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'remove or cleanup enable-background attribute when possible'; + +/** + * Remove or cleanup enable-background attr which coincides with a width/height box. + * + * @see http://www.w3.org/TR/SVG/filters.html#EnableBackgroundProperty + * + * @example + * <svg width="100" height="50" enable-background="new 0 0 100 50"> + * ⬇ + * <svg width="100" height="50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(data) { + + var regEnableBackground = /^new\s0\s0\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)$/, + hasFilter = false, + elems = ['svg', 'mask', 'pattern']; + + function checkEnableBackground(item) { + if ( + item.isElem(elems) && + item.hasAttr('enable-background') && + item.hasAttr('width') && + item.hasAttr('height') + ) { + + var match = item.attr('enable-background').value.match(regEnableBackground); + + if (match) { + if ( + item.attr('width').value === match[1] && + item.attr('height').value === match[3] + ) { + if (item.isElem('svg')) { + item.removeAttr('enable-background'); + } else { + item.attr('enable-background').value = 'new'; + } + } + } + + } + } + + function checkForFilter(item) { + if (item.isElem('filter')) { + hasFilter = true; + } + } + + function monkeys(items, fn) { + items.content.forEach(function(item) { + fn(item); + + if (item.content) { + monkeys(item, fn); + } + }); + return items; + } + + var firstStep = monkeys(data, function(item) { + checkEnableBackground(item); + if (!hasFilter) { + checkForFilter(item); + } + }); + + return hasFilter ? firstStep : monkeys(firstStep, function(item) { + //we don't need 'enable-background' if we have no filters + item.removeAttr('enable-background'); + }); +}; diff --git a/node_modules/svgo/plugins/cleanupIDs.js b/node_modules/svgo/plugins/cleanupIDs.js new file mode 100644 index 00000000..38b5cfb4 --- /dev/null +++ b/node_modules/svgo/plugins/cleanupIDs.js @@ -0,0 +1,208 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'removes unused IDs and minifies used'; + +exports.params = { + remove: true, + minify: true, + prefix: '' +}; + +var referencesProps = require('./_collections').referencesProps, + regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/, + regReferencesHref = /^#(.+?)$/, + regReferencesBegin = /^(\w+?)\./, + styleOrScript = ['style', 'script'], + generateIDchars = [ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' + ], + maxIDindex = generateIDchars.length - 1; + +/** + * Remove unused and minify used IDs + * (only if there are no any <style> or <script>). + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * + * @author Kir Belevich + */ +exports.fn = function(data, params) { + + var currentID, + currentIDstring, + IDs = Object.create(null), + referencesIDs = Object.create(null), + idPrefix = 'id-', // prefix IDs so that values like '__proto__' don't break the work + hasStyleOrScript = false; + + /** + * Bananas! + * + * @param {Array} items input items + * @return {Array} output items + */ + function monkeys(items) { + + for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) { + + var item = items.content[i], + match; + + // check if <style> of <script> presents + if (item.isElem(styleOrScript)) { + hasStyleOrScript = true; + continue; + } + + // …and don't remove any ID if yes + if (item.isElem()) { + + item.eachAttr(function(attr) { + var key; + // save IDs + if (attr.name === 'id') { + key = idPrefix + attr.value; + if (key in IDs) { + item.removeAttr('id'); + } else { + IDs[key] = item; + } + } + + // save IDs url() references + else if (referencesProps.indexOf(attr.name) > -1) { + match = attr.value.match(regReferencesUrl); + + if (match) { + key = idPrefix + match[2]; + if (referencesIDs[key]) { + referencesIDs[key].push(attr); + } else { + referencesIDs[key] = [attr]; + } + } + } + + // save IDs href references + else if ( + attr.local === 'href' && (match = attr.value.match(regReferencesHref)) || + attr.name === 'begin' && (match = attr.value.match(regReferencesBegin)) + ) { + key = idPrefix + match[1]; + if (referencesIDs[key]) { + referencesIDs[key].push(attr); + } else { + referencesIDs[key] = [attr]; + } + } + }); + + } + + // go deeper + if (item.content) { + monkeys(item); + } + } + + return items; + + } + + data = monkeys(data); + + if (hasStyleOrScript) { + return data; + } + + var idKey; + for (var k in referencesIDs) { + if (IDs[k]) { + idKey = k; + k = k.replace(idPrefix, ''); + // replace referenced IDs with the minified ones + if (params.minify) { + currentIDstring = getIDstring(currentID = generateID(currentID), params); + IDs[idKey].attr('id').value = currentIDstring; + + referencesIDs[idKey].forEach(function(attr) { + attr.value = attr.value + .replace('#' + k, '#' + currentIDstring) + .replace(k + '.', currentIDstring + '.'); + }); + + idKey = idPrefix + k; + } + + // don't remove referenced IDs + delete IDs[idKey]; + } + } + + // remove non-referenced IDs attributes from elements + if (params.remove) { + + for(var ID in IDs) { + IDs[ID].removeAttr('id'); + } + + } + + return data; + +}; + +/** + * Generate unique minimal ID. + * + * @param {Array} [currentID] current ID + * @return {Array} generated ID array + */ +function generateID(currentID) { + + if (!currentID) return [0]; + + currentID[currentID.length - 1]++; + + for(var i = currentID.length - 1; i > 0; i--) { + if (currentID[i] > maxIDindex) { + currentID[i] = 0; + + if (currentID[i - 1] !== undefined) { + currentID[i - 1]++; + } + } + } + + if (currentID[0] > maxIDindex) { + currentID[0] = 0; + currentID.unshift(0); + } + + return currentID; + +} + +/** + * Get string from generated ID array. + * + * @param {Array} arr input ID array + * @return {String} output ID string + */ +function getIDstring(arr, params) { + + var str = params.prefix; + + arr.forEach(function(i) { + str += generateIDchars[i]; + }); + + return str; + +} diff --git a/node_modules/svgo/plugins/cleanupListOfValues.js b/node_modules/svgo/plugins/cleanupListOfValues.js new file mode 100644 index 00000000..e75944da --- /dev/null +++ b/node_modules/svgo/plugins/cleanupListOfValues.js @@ -0,0 +1,141 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'rounds list of values to the fixed precision'; + +exports.params = { + floatPrecision: 3, + leadingZero: true, + defaultPx: true, + convertToPx: true +}; + +var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/, + regSeparator = /\s+,?\s*|,\s*/, + removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero, + absoluteLengths = { // relative to px + cm: 96/2.54, + mm: 96/25.4, + in: 96, + pt: 4/3, + pc: 16 + }; + +/** + * Round list of values to the fixed precision. + * + * @example + * <svg viewBox="0 0 200.28423 200.28423" enable-background="new 0 0 200.28423 200.28423"> + * ⬇ + * <svg viewBox="0 0 200.284 200.284" enable-background="new 0 0 200.284 200.284"> + * + * + * <polygon points="208.250977 77.1308594 223.069336 ... "/> + * ⬇ + * <polygon points="208.251 77.131 223.069 ... "/> + * + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author kiyopikko + */ +exports.fn = function(item, params) { + + + if ( item.hasAttr('points') ) { + roundValues(item.attrs.points); + } + + if ( item.hasAttr('enable-background') ) { + roundValues(item.attrs['enable-background']); + } + + if ( item.hasAttr('viewBox') ) { + roundValues(item.attrs.viewBox); + } + + if ( item.hasAttr('stroke-dasharray') ) { + roundValues(item.attrs['stroke-dasharray']); + } + + if ( item.hasAttr('dx') ) { + roundValues(item.attrs.dx); + } + + if ( item.hasAttr('dy') ) { + roundValues(item.attrs.dy); + } + + if ( item.hasAttr('x') ) { + roundValues(item.attrs.x); + } + + if ( item.hasAttr('y') ) { + roundValues(item.attrs.y); + } + + + function roundValues($prop){ + + var num, units, + match, + matchNew, + lists = $prop.value, + listsArr = lists.split(regSeparator), + roundedListArr = [], + roundedList; + + listsArr.forEach(function(elem){ + + match = elem.match(regNumericValues); + matchNew = elem.match(/new/); + + // if attribute value matches regNumericValues + if(match){ + + // round it to the fixed precision + num = +(+match[1]).toFixed(params.floatPrecision), + units = match[3] || ''; + + // convert absolute values to pixels + if (params.convertToPx && units && (units in absoluteLengths)) { + var pxNum = +(absoluteLengths[units] * match[1]).toFixed(params.floatPrecision); + + if (String(pxNum).length < match[0].length) + num = pxNum, + units = 'px'; + } + + // and remove leading zero + if (params.leadingZero) { + num = removeLeadingZero(num); + } + + // remove default 'px' units + if (params.defaultPx && units === 'px') { + units = ''; + } + + roundedListArr.push(num+units); + + } + // if attribute value is "new"(only enable-background). + else if(matchNew){ + + roundedListArr.push('new'); + + } + + }); + + roundedList = roundedListArr.join(' '); + $prop.value = roundedList; + + } + +}; diff --git a/node_modules/svgo/plugins/cleanupNumericValues.js b/node_modules/svgo/plugins/cleanupNumericValues.js new file mode 100644 index 00000000..487443a5 --- /dev/null +++ b/node_modules/svgo/plugins/cleanupNumericValues.js @@ -0,0 +1,76 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'rounds numeric values to the fixed precision, removes default ‘px’ units'; + +exports.params = { + floatPrecision: 3, + leadingZero: true, + defaultPx: true, + convertToPx: true +}; + +var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/, + removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero, + absoluteLengths = { // relative to px + cm: 96/2.54, + mm: 96/25.4, + in: 96, + pt: 4/3, + pc: 16 + }; + +/** + * Round numeric values to the fixed precision, + * remove default 'px' units. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem()) { + + var match; + + item.eachAttr(function(attr) { + match = attr.value.match(regNumericValues); + + // if attribute value matches regNumericValues + if (match) { + // round it to the fixed precision + var num = +(+match[1]).toFixed(params.floatPrecision), + units = match[3] || ''; + + // convert absolute values to pixels + if (params.convertToPx && units && (units in absoluteLengths)) { + var pxNum = +(absoluteLengths[units] * match[1]).toFixed(params.floatPrecision); + + if (String(pxNum).length < match[0].length) + num = pxNum, + units = 'px'; + } + + // and remove leading zero + if (params.leadingZero) { + num = removeLeadingZero(num); + } + + // remove default 'px' units + if (params.defaultPx && units === 'px') { + units = ''; + } + + attr.value = num + units; + } + }); + + } + +}; diff --git a/node_modules/svgo/plugins/collapseGroups.js b/node_modules/svgo/plugins/collapseGroups.js new file mode 100644 index 00000000..adc97638 --- /dev/null +++ b/node_modules/svgo/plugins/collapseGroups.js @@ -0,0 +1,91 @@ +'use strict'; + +exports.type = 'perItemReverse'; + +exports.active = true; + +exports.description = 'collapses useless groups'; + +var collections = require('./_collections'), + attrsInheritable = collections.inheritableAttrs, + animationElems = collections.elemsGroups.animation; + +function hasAnimatedAttr(item) { + /* jshint validthis:true */ + return item.isElem(animationElems) && item.hasAttr('attributeName', this) || + !item.isEmpty() && item.content.some(hasAnimatedAttr, this); +} + +/* + * Collapse useless groups. + * + * @example + * <g> + * <g attr1="val1"> + * <path d="..."/> + * </g> + * </g> + * ⬇ + * <g> + * <g> + * <path attr1="val1" d="..."/> + * </g> + * </g> + * ⬇ + * <path attr1="val1" d="..."/> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + // non-empty elements + if (item.isElem() && !item.isElem('switch') && !item.isEmpty()) { + + item.content.forEach(function(g, i) { + + // non-empty groups + if (g.isElem('g') && !g.isEmpty()) { + + // move group attibutes to the single content element + if (g.hasAttr() && g.content.length === 1) { + var inner = g.content[0]; + + if (inner.isElem() && !inner.hasAttr('id') && + !(g.hasAttr('class') && inner.hasAttr('class')) && ( + !g.hasAttr('clip-path') && !g.hasAttr('mask') || + inner.isElem('g') && !g.hasAttr('transform') && !inner.hasAttr('transform') + ) + ) { + g.eachAttr(function(attr) { + if (g.content.some(hasAnimatedAttr, attr.name)) return; + + if (!inner.hasAttr(attr.name)) { + inner.addAttr(attr); + } else if (attr.name == 'transform') { + inner.attr(attr.name).value = attr.value + ' ' + inner.attr(attr.name).value; + } else if ( + attrsInheritable.indexOf(attr.name) < 0 && + !inner.hasAttr(attr.name, attr.value) + ) { + return; + } + + g.removeAttr(attr.name); + }); + } + } + + // collapse groups without attributes + if (!g.hasAttr() && !g.content.some(function(item) { return item.isElem(animationElems) })) { + item.spliceContent(i, 1, g.content); + } + } + + }); + + } + +}; diff --git a/node_modules/svgo/plugins/convertColors.js b/node_modules/svgo/plugins/convertColors.js new file mode 100644 index 00000000..b856e130 --- /dev/null +++ b/node_modules/svgo/plugins/convertColors.js @@ -0,0 +1,127 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb'; + +exports.params = { + currentColor: false, + names2hex: true, + rgb2hex: true, + shorthex: true, + shortname: true +}; + +var collections = require('./_collections'), + rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)', + rComma = '\\s*,\\s*', + regRGB = new RegExp('^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'), + regHEX = /^\#(([a-fA-F0-9])\2){3}$/, + none = /\bnone\b/i; + +/** + * Convert different colors formats in element attributes to hex. + * + * @see http://www.w3.org/TR/SVG/types.html#DataTypeColor + * @see http://www.w3.org/TR/SVG/single-page.html#types-ColorKeywords + * + * @example + * Convert color name keyword to long hex: + * fuchsia ➡ #ff00ff + * + * Convert rgb() to long hex: + * rgb(255, 0, 255) ➡ #ff00ff + * rgb(50%, 100, 100%) ➡ #7f64ff + * + * Convert long hex to short hex: + * #aabbcc ➡ #abc + * + * Convert hex to short name + * #000080 ➡ navy + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.elem) { + + item.eachAttr(function(attr) { + + if (collections.colorsProps.indexOf(attr.name) > -1) { + + var val = attr.value, + match; + + // Convert colors to currentColor + if (params.currentColor) { + if (typeof params.currentColor === 'string') { + match = val === params.currentColor; + } else if (params.currentColor.exec) { + match = params.currentColor.exec(val); + } else { + match = !val.match(none); + } + if (match) { + val = 'currentColor'; + } + } + + // Convert color name keyword to long hex + if (params.names2hex && val.toLowerCase() in collections.colorsNames) { + val = collections.colorsNames[val.toLowerCase()]; + } + + // Convert rgb() to long hex + if (params.rgb2hex && (match = val.match(regRGB))) { + match = match.slice(1, 4).map(function(m) { + if (m.indexOf('%') > -1) + m = Math.round(parseFloat(m) * 2.55); + + return Math.max(0, Math.min(m, 255)); + }); + + val = rgb2hex(match); + } + + // Convert long hex to short hex + if (params.shorthex && (match = val.match(regHEX))) { + val = '#' + match[0][1] + match[0][3] + match[0][5]; + } + + // Convert hex to short name + if (params.shortname && val in collections.colorsShortNames) { + val = collections.colorsShortNames[val]; + } + + attr.value = val; + + } + + }); + + } + +}; + +/** + * Convert [r, g, b] to #rrggbb. + * + * @see https://gist.github.com/983535 + * + * @example + * rgb2hex([255, 255, 255]) // '#ffffff' + * + * @param {Array} rgb [r, g, b] + * @return {String} #rrggbb + * + * @author Jed Schmidt + */ +function rgb2hex(rgb) { + return '#' + ('00000' + (rgb[0] << 16 | rgb[1] << 8 | rgb[2]).toString(16)).slice(-6).toUpperCase(); +} diff --git a/node_modules/svgo/plugins/convertPathData.js b/node_modules/svgo/plugins/convertPathData.js new file mode 100644 index 00000000..c76a52c2 --- /dev/null +++ b/node_modules/svgo/plugins/convertPathData.js @@ -0,0 +1,957 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'optimizes path data: writes in shorter form, applies transformations'; + +exports.params = { + applyTransforms: true, + applyTransformsStroked: true, + makeArcs: { + threshold: 2.5, // coefficient of rounding error + tolerance: 0.5 // percentage of radius + }, + straightCurves: true, + lineShorthands: true, + curveSmoothShorthands: true, + floatPrecision: 3, + transformPrecision: 5, + removeUseless: true, + collapseRepeated: true, + utilizeAbsolute: true, + leadingZero: true, + negativeExtraSpace: true +}; + +var pathElems = require('./_collections.js').pathElems, + path2js = require('./_path.js').path2js, + js2path = require('./_path.js').js2path, + applyTransforms = require('./_path.js').applyTransforms, + cleanupOutData = require('../lib/svgo/tools').cleanupOutData, + roundData, + precision, + error, + arcThreshold, + arcTolerance, + hasMarkerMid; + +/** + * Convert absolute Path to relative, + * collapse repeated instructions, + * detect and convert Lineto shorthands, + * remove useless instructions like "l0,0", + * trim useless delimiters and leading zeros, + * decrease accuracy of floating-point numbers. + * + * @see http://www.w3.org/TR/SVG/paths.html#PathData + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem(pathElems) && item.hasAttr('d')) { + + precision = params.floatPrecision; + error = precision !== false ? +Math.pow(.1, precision).toFixed(precision) : 1e-2; + roundData = precision > 0 && precision < 20 ? strongRound : round; + if (params.makeArcs) { + arcThreshold = params.makeArcs.threshold; + arcTolerance = params.makeArcs.tolerance; + } + hasMarkerMid = item.hasAttr('marker-mid'); + + var data = path2js(item); + + // TODO: get rid of functions returns + if (data.length) { + convertToRelative(data); + + if (params.applyTransforms) { + data = applyTransforms(item, data, params); + } + + data = filters(data, params); + + if (params.utilizeAbsolute) { + data = convertToMixed(data, params); + } + + js2path(item, data, params); + } + + } + +}; + +/** + * Convert absolute path data coordinates to relative. + * + * @param {Array} path input path data + * @param {Object} params plugin params + * @return {Array} output path data + */ +function convertToRelative(path) { + + var point = [0, 0], + subpathPoint = [0, 0], + baseItem; + + path.forEach(function(item, index) { + + var instruction = item.instruction, + data = item.data; + + // data !== !z + if (data) { + + // already relative + // recalculate current point + if ('mcslqta'.indexOf(instruction) > -1) { + + point[0] += data[data.length - 2]; + point[1] += data[data.length - 1]; + + if (instruction === 'm') { + subpathPoint[0] = point[0]; + subpathPoint[1] = point[1]; + baseItem = item; + } + + } else if (instruction === 'h') { + + point[0] += data[0]; + + } else if (instruction === 'v') { + + point[1] += data[0]; + + } + + // convert absolute path data coordinates to relative + // if "M" was not transformed from "m" + // M → m + if (instruction === 'M') { + + if (index > 0) instruction = 'm'; + + data[0] -= point[0]; + data[1] -= point[1]; + + subpathPoint[0] = point[0] += data[0]; + subpathPoint[1] = point[1] += data[1]; + + baseItem = item; + + } + + // L → l + // T → t + else if ('LT'.indexOf(instruction) > -1) { + + instruction = instruction.toLowerCase(); + + // x y + // 0 1 + data[0] -= point[0]; + data[1] -= point[1]; + + point[0] += data[0]; + point[1] += data[1]; + + // C → c + } else if (instruction === 'C') { + + instruction = 'c'; + + // x1 y1 x2 y2 x y + // 0 1 2 3 4 5 + data[0] -= point[0]; + data[1] -= point[1]; + data[2] -= point[0]; + data[3] -= point[1]; + data[4] -= point[0]; + data[5] -= point[1]; + + point[0] += data[4]; + point[1] += data[5]; + + // S → s + // Q → q + } else if ('SQ'.indexOf(instruction) > -1) { + + instruction = instruction.toLowerCase(); + + // x1 y1 x y + // 0 1 2 3 + data[0] -= point[0]; + data[1] -= point[1]; + data[2] -= point[0]; + data[3] -= point[1]; + + point[0] += data[2]; + point[1] += data[3]; + + // A → a + } else if (instruction === 'A') { + + instruction = 'a'; + + // rx ry x-axis-rotation large-arc-flag sweep-flag x y + // 0 1 2 3 4 5 6 + data[5] -= point[0]; + data[6] -= point[1]; + + point[0] += data[5]; + point[1] += data[6]; + + // H → h + } else if (instruction === 'H') { + + instruction = 'h'; + + data[0] -= point[0]; + + point[0] += data[0]; + + // V → v + } else if (instruction === 'V') { + + instruction = 'v'; + + data[0] -= point[1]; + + point[1] += data[0]; + + } + + item.instruction = instruction; + item.data = data; + + // store absolute coordinates for later use + item.coords = point.slice(-2); + + } + + // !data === z, reset current point + else if (instruction == 'z') { + if (baseItem) { + item.coords = baseItem.coords; + } + point[0] = subpathPoint[0]; + point[1] = subpathPoint[1]; + } + + item.base = index > 0 ? path[index - 1].coords : [0, 0]; + + }); + + return path; + +} + +/** + * Main filters loop. + * + * @param {Array} path input path data + * @param {Object} params plugin params + * @return {Array} output path data + */ +function filters(path, params) { + + var stringify = data2Path.bind(null, params), + relSubpoint = [0, 0], + pathBase = [0, 0], + prev = {}; + + path = path.filter(function(item, index, path) { + + var instruction = item.instruction, + data = item.data, + next = path[index + 1]; + + if (data) { + + var sdata = data, + circle; + + if (instruction === 's') { + sdata = [0, 0].concat(data); + + if ('cs'.indexOf(prev.instruction) > -1) { + var pdata = prev.data, + n = pdata.length; + + // (-x, -y) of the prev tangent point relative to the current point + sdata[0] = pdata[n - 2] - pdata[n - 4]; + sdata[1] = pdata[n - 1] - pdata[n - 3]; + } + + } + + // convert curves to arcs if possible + if ( + params.makeArcs && + (instruction == 'c' || instruction == 's') && + isConvex(sdata) && + (circle = findCircle(sdata)) + ) { + var r = roundData([circle.radius])[0], + angle = findArcAngle(sdata, circle), + sweep = sdata[5] * sdata[0] - sdata[4] * sdata[1] > 0 ? 1 : 0, + arc = { + instruction: 'a', + data: [r, r, 0, 0, sweep, sdata[4], sdata[5]], + coords: item.coords.slice(), + base: item.base + }, + output = [arc], + // relative coordinates to adjust the found circle + relCenter = [circle.center[0] - sdata[4], circle.center[1] - sdata[5]], + relCircle = { center: relCenter, radius: circle.radius }, + arcCurves = [item], + hasPrev = 0, + suffix = '', + nextLonghand; + + if ( + prev.instruction == 'c' && isConvex(prev.data) && isArcPrev(prev.data, circle) || + prev.instruction == 'a' && prev.sdata && isArcPrev(prev.sdata, circle) + ) { + arcCurves.unshift(prev); + arc.base = prev.base; + arc.data[5] = arc.coords[0] - arc.base[0]; + arc.data[6] = arc.coords[1] - arc.base[1]; + var prevData = prev.instruction == 'a' ? prev.sdata : prev.data; + angle += findArcAngle(prevData, + { + center: [prevData[4] + relCenter[0], prevData[5] + relCenter[1]], + radius: circle.radius + } + ); + if (angle > Math.PI) arc.data[3] = 1; + hasPrev = 1; + } + + // check if next curves are fitting the arc + for (var j = index; (next = path[++j]) && ~'cs'.indexOf(next.instruction);) { + var nextData = next.data; + if (next.instruction == 's') { + nextLonghand = makeLonghand({instruction: 's', data: next.data.slice() }, + path[j - 1].data); + nextData = nextLonghand.data; + nextLonghand.data = nextData.slice(0, 2); + suffix = stringify([nextLonghand]); + } + if (isConvex(nextData) && isArc(nextData, relCircle)) { + angle += findArcAngle(nextData, relCircle); + if (angle - 2 * Math.PI > 1e-3) break; // more than 360° + if (angle > Math.PI) arc.data[3] = 1; + arcCurves.push(next); + if (2 * Math.PI - angle > 1e-3) { // less than 360° + arc.coords = next.coords; + arc.data[5] = arc.coords[0] - arc.base[0]; + arc.data[6] = arc.coords[1] - arc.base[1]; + } else { + // full circle, make a half-circle arc and add a second one + arc.data[5] = 2 * (relCircle.center[0] - nextData[4]); + arc.data[6] = 2 * (relCircle.center[1] - nextData[5]); + arc.coords = [arc.base[0] + arc.data[5], arc.base[1] + arc.data[6]]; + arc = { + instruction: 'a', + data: [r, r, 0, 0, sweep, + next.coords[0] - arc.coords[0], next.coords[1] - arc.coords[1]], + coords: next.coords, + base: arc.coords + }; + output.push(arc); + j++; + break; + } + relCenter[0] -= nextData[4]; + relCenter[1] -= nextData[5]; + } else break; + } + + if ((stringify(output) + suffix).length < stringify(arcCurves).length) { + if (path[j] && path[j].instruction == 's') { + makeLonghand(path[j], path[j - 1].data); + } + if (hasPrev) { + var prevArc = output.shift(); + roundData(prevArc.data); + relSubpoint[0] += prevArc.data[5] - prev.data[prev.data.length - 2]; + relSubpoint[1] += prevArc.data[6] - prev.data[prev.data.length - 1]; + prev.instruction = 'a'; + prev.data = prevArc.data; + item.base = prev.coords = prevArc.coords; + } + arc = output.shift(); + if (arcCurves.length == 1) { + item.sdata = sdata.slice(); // preserve curve data for future checks + } else if (arcCurves.length - 1 - hasPrev > 0) { + // filter out consumed next items + path.splice.apply(path, [index + 1, arcCurves.length - 1 - hasPrev].concat(output)); + } + if (!arc) return false; + instruction = 'a'; + data = arc.data; + item.coords = arc.coords; + } + } + + // Rounding relative coordinates, taking in account accummulating error + // to get closer to absolute coordinates. Sum of rounded value remains same: + // l .25 3 .25 2 .25 3 .25 2 -> l .3 3 .2 2 .3 3 .2 2 + if (precision !== false) { + if ('mltqsc'.indexOf(instruction) > -1) { + for (var i = data.length; i--;) { + data[i] += item.base[i % 2] - relSubpoint[i % 2]; + } + } else if (instruction == 'h') { + data[0] += item.base[0] - relSubpoint[0]; + } else if (instruction == 'v') { + data[0] += item.base[1] - relSubpoint[1]; + } else if (instruction == 'a') { + data[5] += item.base[0] - relSubpoint[0]; + data[6] += item.base[1] - relSubpoint[1]; + } + roundData(data); + + if (instruction == 'h') relSubpoint[0] += data[0]; + else if (instruction == 'v') relSubpoint[1] += data[0]; + else { + relSubpoint[0] += data[data.length - 2]; + relSubpoint[1] += data[data.length - 1]; + } + roundData(relSubpoint); + + if (instruction.toLowerCase() == 'm') { + pathBase[0] = relSubpoint[0]; + pathBase[1] = relSubpoint[1]; + } + } + + // convert straight curves into lines segments + if (params.straightCurves) { + + if ( + instruction === 'c' && + isCurveStraightLine(data) || + instruction === 's' && + isCurveStraightLine(sdata) + ) { + if (next && next.instruction == 's') + makeLonghand(next, data); // fix up next curve + instruction = 'l'; + data = data.slice(-2); + } + + else if ( + instruction === 'q' && + isCurveStraightLine(data) + ) { + if (next && next.instruction == 't') + makeLonghand(next, data); // fix up next curve + instruction = 'l'; + data = data.slice(-2); + } + + else if ( + instruction === 't' && + prev.instruction !== 'q' && + prev.instruction !== 't' + ) { + instruction = 'l'; + data = data.slice(-2); + } + + else if ( + instruction === 'a' && + (data[0] === 0 || data[1] === 0) + ) { + instruction = 'l'; + data = data.slice(-2); + } + } + + // horizontal and vertical line shorthands + // l 50 0 → h 50 + // l 0 50 → v 50 + if ( + params.lineShorthands && + instruction === 'l' + ) { + if (data[1] === 0) { + instruction = 'h'; + data.pop(); + } else if (data[0] === 0) { + instruction = 'v'; + data.shift(); + } + } + + // collapse repeated commands + // h 20 h 30 -> h 50 + if ( + params.collapseRepeated && + !hasMarkerMid && + ('mhv'.indexOf(instruction) > -1) && + prev.instruction && + instruction == prev.instruction.toLowerCase() && + ( + (instruction != 'h' && instruction != 'v') || + (prev.data[0] >= 0) == (item.data[0] >= 0) + )) { + prev.data[0] += data[0]; + if (instruction != 'h' && instruction != 'v') { + prev.data[1] += data[1]; + } + prev.coords = item.coords; + path[index] = prev; + return false; + } + + // convert curves into smooth shorthands + if (params.curveSmoothShorthands && prev.instruction) { + + // curveto + if (instruction === 'c') { + + // c + c → c + s + if ( + prev.instruction === 'c' && + data[0] === -(prev.data[2] - prev.data[4]) && + data[1] === -(prev.data[3] - prev.data[5]) + ) { + instruction = 's'; + data = data.slice(2); + } + + // s + c → s + s + else if ( + prev.instruction === 's' && + data[0] === -(prev.data[0] - prev.data[2]) && + data[1] === -(prev.data[1] - prev.data[3]) + ) { + instruction = 's'; + data = data.slice(2); + } + + // [^cs] + c → [^cs] + s + else if ( + 'cs'.indexOf(prev.instruction) === -1 && + data[0] === 0 && + data[1] === 0 + ) { + instruction = 's'; + data = data.slice(2); + } + + } + + // quadratic Bézier curveto + else if (instruction === 'q') { + + // q + q → q + t + if ( + prev.instruction === 'q' && + data[0] === (prev.data[2] - prev.data[0]) && + data[1] === (prev.data[3] - prev.data[1]) + ) { + instruction = 't'; + data = data.slice(2); + } + + // t + q → t + t + else if ( + prev.instruction === 't' && + data[2] === prev.data[0] && + data[3] === prev.data[1] + ) { + instruction = 't'; + data = data.slice(2); + } + + } + + } + + // remove useless non-first path segments + if (params.removeUseless) { + + // l 0,0 / h 0 / v 0 / q 0,0 0,0 / t 0,0 / c 0,0 0,0 0,0 / s 0,0 0,0 + if ( + ( + 'lhvqtcs'.indexOf(instruction) > -1 + ) && + data.every(function(i) { return i === 0; }) + ) { + path[index] = prev; + return false; + } + + // a 25,25 -30 0,1 0,0 + if ( + instruction === 'a' && + data[5] === 0 && + data[6] === 0 + ) { + path[index] = prev; + return false; + } + + } + + item.instruction = instruction; + item.data = data; + + prev = item; + + } else { + + // z resets coordinates + relSubpoint[0] = pathBase[0]; + relSubpoint[1] = pathBase[1]; + if (prev.instruction == 'z') return false; + prev = item; + + } + + return true; + + }); + + return path; + +} + +/** + * Writes data in shortest form using absolute or relative coordinates. + * + * @param {Array} data input path data + * @return {Boolean} output + */ +function convertToMixed(path, params) { + + var prev = path[0]; + + path = path.filter(function(item, index) { + + if (index == 0) return true; + if (!item.data) { + prev = item; + return true; + } + + var instruction = item.instruction, + data = item.data, + adata = data && data.slice(0); + + if ('mltqsc'.indexOf(instruction) > -1) { + for (var i = adata.length; i--;) { + adata[i] += item.base[i % 2]; + } + } else if (instruction == 'h') { + adata[0] += item.base[0]; + } else if (instruction == 'v') { + adata[0] += item.base[1]; + } else if (instruction == 'a') { + adata[5] += item.base[0]; + adata[6] += item.base[1]; + } + + roundData(adata); + + var absoluteDataStr = cleanupOutData(adata, params), + relativeDataStr = cleanupOutData(data, params); + + // Convert to absolute coordinates if it's shorter. + // v-20 -> V0 + // Don't convert if it fits following previous instruction. + // l20 30-10-50 instead of l20 30L20 30 + if ( + absoluteDataStr.length < relativeDataStr.length && + !( + params.negativeExtraSpace && + instruction == prev.instruction && + prev.instruction.charCodeAt(0) > 96 && + absoluteDataStr.length == relativeDataStr.length - 1 && + (data[0] < 0 || /^0\./.test(data[0]) && prev.data[prev.data.length - 1] % 1) + ) + ) { + item.instruction = instruction.toUpperCase(); + item.data = adata; + } + + prev = item; + + return true; + + }); + + return path; + +} + +/** + * Checks if curve is convex. Control points of such a curve must form + * a convex quadrilateral with diagonals crosspoint inside of it. + * + * @param {Array} data input path data + * @return {Boolean} output + */ +function isConvex(data) { + + var center = getIntersection([0, 0, data[2], data[3], data[0], data[1], data[4], data[5]]); + + return center && + (data[2] < center[0] == center[0] < 0) && + (data[3] < center[1] == center[1] < 0) && + (data[4] < center[0] == center[0] < data[0]) && + (data[5] < center[1] == center[1] < data[1]); + +} + +/** + * Computes lines equations by two points and returns their intersection point. + * + * @param {Array} coords 8 numbers for 4 pairs of coordinates (x,y) + * @return {Array|undefined} output coordinate of lines' crosspoint + */ +function getIntersection(coords) { + + // Prev line equation parameters. + var a1 = coords[1] - coords[3], // y1 - y2 + b1 = coords[2] - coords[0], // x2 - x1 + c1 = coords[0] * coords[3] - coords[2] * coords[1], // x1 * y2 - x2 * y1 + + // Next line equation parameters + a2 = coords[5] - coords[7], // y1 - y2 + b2 = coords[6] - coords[4], // x2 - x1 + c2 = coords[4] * coords[7] - coords[5] * coords[6], // x1 * y2 - x2 * y1 + denom = (a1 * b2 - a2 * b1); + + if (!denom) return; // parallel lines havn't an intersection + + var cross = [ + (b1 * c2 - b2 * c1) / denom, + (a1 * c2 - a2 * c1) / -denom + ]; + if ( + !isNaN(cross[0]) && !isNaN(cross[1]) && + isFinite(cross[0]) && isFinite(cross[1]) + ) { + return cross; + } + +} + +/** + * Decrease accuracy of floating-point numbers + * in path data keeping a specified number of decimals. + * Smart rounds values like 2.3491 to 2.35 instead of 2.349. + * Doesn't apply "smartness" if the number precision fits already. + * + * @param {Array} data input data array + * @return {Array} output data array + */ +function strongRound(data) { + for (var i = data.length; i-- > 0;) { + if (data[i].toFixed(precision) != data[i]) { + var rounded = +data[i].toFixed(precision - 1); + data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= error ? + +data[i].toFixed(precision) : + rounded; + } + } + return data; +} + +/** + * Simple rounding function if precision is 0. + * + * @param {Array} data input data array + * @return {Array} output data array + */ +function round(data) { + for (var i = data.length; i-- > 0;) { + data[i] = Math.round(data[i]); + } + return data; +} + +/** + * Checks if a curve is a straight line by measuring distance + * from middle points to the line formed by end points. + * + * @param {Array} xs array of curve points x-coordinates + * @param {Array} ys array of curve points y-coordinates + * @return {Boolean} + */ + +function isCurveStraightLine(data) { + + // Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points. + var i = data.length - 2, + a = -data[i + 1], // y1 − y2 (y1 = 0) + b = data[i], // x2 − x1 (x1 = 0) + d = 1 / (a * a + b * b); // same part for all points + + if (i <= 1 || !isFinite(d)) return false; // curve that ends at start point isn't the case + + // Distance from point (x0, y0) to the line is sqrt((c − a·x0 − b·y0)² / (a² + b²)) + while ((i -= 2) >= 0) { + if (Math.sqrt(Math.pow(a * data[i] + b * data[i + 1], 2) * d) > error) + return false; + } + + return true; + +} + +/** + * Converts next curve from shorthand to full form using the current curve data. + * + * @param {Object} item curve to convert + * @param {Array} data current curve data + */ + +function makeLonghand(item, data) { + switch (item.instruction) { + case 's': item.instruction = 'c'; break; + case 't': item.instruction = 'q'; break; + } + item.data.unshift(data[data.length - 2] - data[data.length - 4], data[data.length - 1] - data[data.length - 3]); + return item; +} + +/** + * Returns distance between two points + * + * @param {Array} point1 first point coordinates + * @param {Array} point2 second point coordinates + * @return {Number} distance + */ + +function getDistance(point1, point2) { + return Math.sqrt(Math.pow(point1[0] - point2[0], 2) + Math.pow(point1[1] - point2[1], 2)); +} + +/** + * Returns coordinates of the curve point corresponding to the certain t + * a·(1 - t)³·p1 + b·(1 - t)²·t·p2 + c·(1 - t)·t²·p3 + d·t³·p4, + * where pN are control points and p1 is zero due to relative coordinates. + * + * @param {Array} curve array of curve points coordinates + * @param {Number} t parametric position from 0 to 1 + * @return {Array} Point coordinates + */ + +function getCubicBezierPoint(curve, t) { + var sqrT = t * t, + cubT = sqrT * t, + mt = 1 - t, + sqrMt = mt * mt; + + return [ + 3 * sqrMt * t * curve[0] + 3 * mt * sqrT * curve[2] + cubT * curve[4], + 3 * sqrMt * t * curve[1] + 3 * mt * sqrT * curve[3] + cubT * curve[5] + ]; +} + +/** + * Finds circle by 3 points of the curve and checks if the curve fits the found circle. + * + * @param {Array} curve + * @return {Object|undefined} circle + */ + +function findCircle(curve) { + var midPoint = getCubicBezierPoint(curve, 1/2), + m1 = [midPoint[0] / 2, midPoint[1] / 2], + m2 = [(midPoint[0] + curve[4]) / 2, (midPoint[1] + curve[5]) / 2], + center = getIntersection([ + m1[0], m1[1], + m1[0] + m1[1], m1[1] - m1[0], + m2[0], m2[1], + m2[0] + (m2[1] - midPoint[1]), m2[1] - (m2[0] - midPoint[0]) + ]), + radius = center && getDistance([0, 0], center), + tolerance = Math.min(arcThreshold * error, arcTolerance * radius / 100); + + if (center && [1/4, 3/4].every(function(point) { + return Math.abs(getDistance(getCubicBezierPoint(curve, point), center) - radius) <= tolerance; + })) + return { center: center, radius: radius}; +} + +/** + * Checks if a curve fits the given circe. + * + * @param {Object} circle + * @param {Array} curve + * @return {Boolean} + */ + +function isArc(curve, circle) { + var tolerance = Math.min(arcThreshold * error, arcTolerance * circle.radius / 100); + + return [0, 1/4, 1/2, 3/4, 1].every(function(point) { + return Math.abs(getDistance(getCubicBezierPoint(curve, point), circle.center) - circle.radius) <= tolerance; + }); +} + +/** + * Checks if a previos curve fits the given circe. + * + * @param {Object} circle + * @param {Array} curve + * @return {Boolean} + */ + +function isArcPrev(curve, circle) { + return isArc(curve, { + center: [circle.center[0] + curve[4], circle.center[1] + curve[5]], + radius: circle.radius + }); +} + +/** + * Finds angle of a curve fitting the given arc. + + * @param {Array} curve + * @param {Object} relCircle + * @return {Number} angle + */ + +function findArcAngle(curve, relCircle) { + var x1 = -relCircle.center[0], + y1 = -relCircle.center[1], + x2 = curve[4] - relCircle.center[0], + y2 = curve[5] - relCircle.center[1]; + + return Math.acos( + (x1 * x2 + y1 * y2) / + Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) + ); +} + +/** + * Converts given path data to string. + * + * @param {Object} params + * @param {Array} pathData + * @return {String} + */ + +function data2Path(params, pathData) { + return pathData.reduce(function(pathString, item) { + return pathString += item.instruction + (item.data ? cleanupOutData(roundData(item.data.slice()), params) : ''); + }, ''); +} diff --git a/node_modules/svgo/plugins/convertShapeToPath.js b/node_modules/svgo/plugins/convertShapeToPath.js new file mode 100644 index 00000000..6d328049 --- /dev/null +++ b/node_modules/svgo/plugins/convertShapeToPath.js @@ -0,0 +1,103 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts basic shapes to more compact path form'; + +var none = { value: 0 }, + regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; + +/** + * Converts basic shape to more compact path. + * It also allows further optimizations like + * combining paths with similar attributes. + * + * @see http://www.w3.org/TR/SVG/shapes.html + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Lev Solntsev + */ +exports.fn = function(item) { + + if ( + item.isElem('rect') && + item.hasAttr('width') && + item.hasAttr('height') && + !item.hasAttr('rx') && + !item.hasAttr('ry') + ) { + + var x = +(item.attr('x') || none).value, + y = +(item.attr('y') || none).value, + width = +item.attr('width').value, + height = +item.attr('height').value; + + // Values like '100%' compute to NaN, thus running after + // cleanupNumericValues when 'px' units has already been removed. + // TODO: Calculate sizes from % and non-px units if possible. + if (isNaN(x - y + width - height)) return; + + var pathData = + 'M' + x + ' ' + y + + 'H' + (x + width) + + 'V' + (y + height) + + 'H' + x + + 'z'; + + item.addAttr({ + name: 'd', + value: pathData, + prefix: '', + local: 'd' + }); + + item.renameElem('path') + .removeAttr(['x', 'y', 'width', 'height']); + + } else if (item.isElem('line')) { + + var x1 = +(item.attr('x1') || none).value, + y1 = +(item.attr('y1') || none).value, + x2 = +(item.attr('x2') || none).value, + y2 = +(item.attr('y2') || none).value; + if (isNaN(x1 - y1 + x2 - y2)) return; + + item.addAttr({ + name: 'd', + value: 'M' + x1 + ' ' + y1 + 'L' + x2 + ' ' + y2, + prefix: '', + local: 'd' + }); + + item.renameElem('path') + .removeAttr(['x1', 'y1', 'x2', 'y2']); + + } else if (( + item.isElem('polyline') || + item.isElem('polygon') + ) && + item.hasAttr('points') + ) { + + var coords = (item.attr('points').value.match(regNumber) || []).map(Number); + if (coords.length < 4) return false; + + item.addAttr({ + name: 'd', + value: 'M' + coords.slice(0,2).join(' ') + + 'L' + coords.slice(2).join(' ') + + (item.isElem('polygon') ? 'z' : ''), + prefix: '', + local: 'd' + }); + + item.renameElem('path') + .removeAttr('points'); + } + +}; diff --git a/node_modules/svgo/plugins/convertStyleToAttrs.js b/node_modules/svgo/plugins/convertStyleToAttrs.js new file mode 100644 index 00000000..02bbc550 --- /dev/null +++ b/node_modules/svgo/plugins/convertStyleToAttrs.js @@ -0,0 +1,117 @@ +/* jshint quotmark: false */ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts style to attributes'; + +var EXTEND = require('whet.extend'), + stylingProps = require('./_collections').attrsGroups.presentation, + rEscape = '\\\\(?:[0-9a-f]{1,6}\\s?|\\r\\n|.)', // Like \" or \2051. Code points consume one space. + rAttr = '\\s*(' + g('[^:;\\\\]', rEscape) + '*?)\\s*', // attribute name like ‘fill’ + rSingleQuotes = "'(?:[^'\\n\\r\\\\]|" + rEscape + ")*?(?:'|$)", // string in single quotes: 'smth' + rQuotes = '"(?:[^"\\n\\r\\\\]|' + rEscape + ')*?(?:"|$)', // string in double quotes: "smth" + rQuotedString = new RegExp('^' + g(rSingleQuotes, rQuotes) + '$'), + + // Parentheses, E.g.: url(data:image/png;base64,iVBO...). + // ':' and ';' inside of it should be threated as is. (Just like in strings.) + rParenthesis = '\\(' + g('[^\'"()\\\\]+', rEscape, rSingleQuotes, rQuotes) + '*?' + '\\)', + + // The value. It can have strings and parentheses (see above). Fallbacks to anything in case of unexpected input. + rValue = '\\s*(' + g('[^\'"();\\\\]+?', rEscape, rSingleQuotes, rQuotes, rParenthesis, '[^;]*?') + '*?' + ')', + + // End of declaration. Spaces outside of capturing groups help to do natural trimming. + rDeclEnd = '\\s*(?:;\\s*|$)', + + // Final RegExp to parse CSS declarations. + regDeclarationBlock = new RegExp(rAttr + ':' + rValue + rDeclEnd, 'ig'), + + // Comments expression. Honors escape sequences and strings. + regStripComments = new RegExp(g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'), 'ig'); + +/** + * Convert style in attributes. Cleanups comments and illegal declarations (without colon) as a side effect. + * + * @example + * <g style="fill:#000; color: #fff;"> + * ⬇ + * <g fill="#000" color="#fff"> + * + * @example + * <g style="fill:#000; color: #fff; -webkit-blah: blah"> + * ⬇ + * <g fill="#000" color="#fff" style="-webkit-blah: blah"> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + /* jshint boss: true */ + + if (item.elem && item.hasAttr('style')) { + // ['opacity: 1', 'color: #000'] + var styleValue = item.attr('style').value, + styles = [], + attrs = {}; + + // Strip CSS comments preserving escape sequences and strings. + styleValue = styleValue.replace(regStripComments, function(match) { + return match[0] == '/' ? '' : + match[0] == '\\' && /[-g-z]/i.test(match[1]) ? match[1] : match; + }); + + regDeclarationBlock.lastIndex = 0; + for (var rule; rule = regDeclarationBlock.exec(styleValue);) { + styles.push([rule[1], rule[2]]); + } + + if (styles.length) { + + styles = styles.filter(function(style) { + if (style[0]) { + var prop = style[0].toLowerCase(), + val = style[1]; + + if (rQuotedString.test(val)) { + val = val.slice(1, -1); + } + + if (stylingProps.indexOf(prop) > -1) { + + attrs[prop] = { + name: prop, + value: val, + local: prop, + prefix: '' + }; + + return false; + } + } + + return true; + }); + + EXTEND(item.attrs, attrs); + + if (styles.length) { + item.attr('style').value = styles + .map(function(declaration) { return declaration.join(':') }) + .join(';'); + } else { + item.removeAttr('style'); + } + + } + + } + +}; + +function g() { + return '(?:' + Array.prototype.join.call(arguments, '|') + ')'; +} diff --git a/node_modules/svgo/plugins/convertTransform.js b/node_modules/svgo/plugins/convertTransform.js new file mode 100644 index 00000000..c2085892 --- /dev/null +++ b/node_modules/svgo/plugins/convertTransform.js @@ -0,0 +1,364 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'collapses multiple transformations and optimizes it'; + +exports.params = { + convertToShorts: true, + // degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default + floatPrecision: 3, + transformPrecision: 5, + matrixToTransform: true, + shortTranslate: true, + shortScale: true, + shortRotate: true, + removeUseless: true, + collapseIntoOne: true, + leadingZero: true, + negativeExtraSpace: false +}; + +var cleanupOutData = require('../lib/svgo/tools').cleanupOutData, + EXTEND = require('whet.extend'), + transform2js = require('./_transforms.js').transform2js, + transformsMultiply = require('./_transforms.js').transformsMultiply, + matrixToTransform = require('./_transforms.js').matrixToTransform, + degRound, + floatRound, + transformRound; + +/** + * Convert matrices to the short aliases, + * convert long translate, scale or rotate transform notations to the shorts ones, + * convert transforms to the matrices and multiply them all into one, + * remove useless transforms. + * + * @see http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.elem) { + + // transform + if (item.hasAttr('transform')) { + convertTransform(item, 'transform', params); + } + + // gradientTransform + if (item.hasAttr('gradientTransform')) { + convertTransform(item, 'gradientTransform', params); + } + + // patternTransform + if (item.hasAttr('patternTransform')) { + convertTransform(item, 'patternTransform', params); + } + + } + +}; + +/** + * Main function. + * + * @param {Object} item input item + * @param {String} attrName attribute name + * @param {Object} params plugin params + */ +function convertTransform(item, attrName, params) { + var data = transform2js(item.attr(attrName).value); + params = definePrecision(data, params); + + if (params.collapseIntoOne && data.length > 1) { + data = [transformsMultiply(data)]; + } + + if (params.convertToShorts) { + data = convertToShorts(data, params); + } else { + data.forEach(roundTransform); + } + + if (params.removeUseless) { + data = removeUseless(data); + } + + if (data.length) { + item.attr(attrName).value = js2transform(data, params); + } else { + item.removeAttr(attrName); + } +} + +/** + * Defines precision to work with certain parts. + * transformPrecision - for scale and four first matrix parameters (needs a better precision due to multiplying), + * floatPrecision - for translate including two last matrix and rotate parameters, + * degPrecision - for rotate and skew. By default it's equal to (rougly) + * transformPrecision - 2 or floatPrecision whichever is lower. Can be set in params. + * + * @param {Array} transforms input array + * @param {Object} params plugin params + * @return {Array} output array + */ +function definePrecision(data, params) { + /* jshint validthis: true */ + var matrixData = data.reduce(getMatrixData, []), + significantDigits = params.transformPrecision; + + // Clone params so it don't affect other elements transformations. + params = EXTEND({}, params); + + // Limit transform precision with matrix one. Calculating with larger precision doesn't add any value. + if (matrixData.length) { + params.transformPrecision = Math.min(params.transformPrecision, + Math.max.apply(Math, matrixData.map(floatDigits)) || params.transformPrecision); + + significantDigits = Math.max.apply(Math, matrixData.map(function(n) { + return String(n).replace(/\D+/g, '').length; // Number of digits in a number. 123.45 → 5 + })); + } + // No sense in angle precision more then number of significant digits in matrix. + if (!('degPrecision' in params)) { + params.degPrecision = Math.max(0, Math.min(params.floatPrecision, significantDigits - 2)); + } + + floatRound = params.floatPrecision >= 1 && params.floatPrecision < 20 ? + smartRound.bind(this, params.floatPrecision) : + round; + degRound = params.degPrecision >= 1 && params.floatPrecision < 20 ? + smartRound.bind(this, params.degPrecision) : + round; + transformRound = params.transformPrecision >= 1 && params.floatPrecision < 20 ? + smartRound.bind(this, params.transformPrecision) : + round; + + return params; +} + +/** + * Gathers four first matrix parameters. + * + * @param {Array} a array of data + * @param {Object} transform + * @return {Array} output array + */ +function getMatrixData(a, b) { + return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a; +} + +/** + * Returns number of digits after the point. 0.125 → 3 + */ +function floatDigits(n) { + return (n = String(n)).slice(n.indexOf('.')).length - 1; +} + +/** + * Convert transforms to the shorthand alternatives. + * + * @param {Array} transforms input array + * @param {Object} params plugin params + * @return {Array} output array + */ +function convertToShorts(transforms, params) { + + for(var i = 0; i < transforms.length; i++) { + + var transform = transforms[i]; + + // convert matrix to the short aliases + if ( + params.matrixToTransform && + transform.name === 'matrix' + ) { + var decomposed = matrixToTransform(transform, params); + if (decomposed != transform && + js2transform(decomposed, params).length <= js2transform([transform], params).length) { + + transforms.splice.apply(transforms, [i, 1].concat(decomposed)); + } + transform = transforms[i]; + } + + // fixed-point numbers + // 12.754997 → 12.755 + roundTransform(transform); + + // convert long translate transform notation to the shorts one + // translate(10 0) → translate(10) + if ( + params.shortTranslate && + transform.name === 'translate' && + transform.data.length === 2 && + !transform.data[1] + ) { + transform.data.pop(); + } + + // convert long scale transform notation to the shorts one + // scale(2 2) → scale(2) + if ( + params.shortScale && + transform.name === 'scale' && + transform.data.length === 2 && + transform.data[0] === transform.data[1] + ) { + transform.data.pop(); + } + + // convert long rotate transform notation to the short one + // translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy) + if ( + params.shortRotate && + transforms[i - 2] && + transforms[i - 2].name === 'translate' && + transforms[i - 1].name === 'rotate' && + transforms[i].name === 'translate' && + transforms[i - 2].data[0] === -transforms[i].data[0] && + transforms[i - 2].data[1] === -transforms[i].data[1] + ) { + transforms.splice(i - 2, 3, { + name: 'rotate', + data: [ + transforms[i - 1].data[0], + transforms[i - 2].data[0], + transforms[i - 2].data[1] + ] + }); + + // splice compensation + i -= 2; + + transform = transforms[i]; + } + + } + + return transforms; + +} + +/** + * Remove useless transforms. + * + * @param {Array} transforms input array + * @return {Array} output array + */ +function removeUseless(transforms) { + + return transforms.filter(function(transform) { + + // translate(0), rotate(0[, cx, cy]), skewX(0), skewY(0) + if ( + ['translate', 'rotate', 'skewX', 'skewY'].indexOf(transform.name) > -1 && + (transform.data.length == 1 || transform.name == 'rotate') && + !transform.data[0] || + + // translate(0, 0) + transform.name == 'translate' && + !transform.data[0] && + !transform.data[1] || + + // scale(1) + transform.name == 'scale' && + transform.data[0] == 1 && + (transform.data.length < 2 || transform.data[1] == 1) || + + // matrix(1 0 0 1 0 0) + transform.name == 'matrix' && + transform.data[0] == 1 && + transform.data[3] == 1 && + !(transform.data[1] || transform.data[2] || transform.data[4] || transform.data[5]) + ) { + return false; + } + + return true; + + }); + +} + +/** + * Convert transforms JS representation to string. + * + * @param {Array} transformJS JS representation array + * @param {Object} params plugin params + * @return {String} output string + */ +function js2transform(transformJS, params) { + + var transformString = ''; + + // collect output value string + transformJS.forEach(function(transform) { + roundTransform(transform); + transformString += (transformString && ' ') + transform.name + '(' + cleanupOutData(transform.data, params) + ')'; + }); + + return transformString; + +} + +function roundTransform(transform) { + switch (transform.name) { + case 'translate': + transform.data = floatRound(transform.data); + break; + case 'rotate': + transform.data = degRound(transform.data.slice(0, 1)).concat(floatRound(transform.data.slice(1))); + break; + case 'skewX': + case 'skewY': + transform.data = degRound(transform.data); + break; + case 'scale': + transform.data = transformRound(transform.data); + break; + case 'matrix': + transform.data = transformRound(transform.data.slice(0, 4)).concat(floatRound(transform.data.slice(4))); + break; + } + return transform; +} + +/** + * Rounds numbers in array. + * + * @param {Array} data input data array + * @return {Array} output data array + */ +function round(data) { + return data.map(Math.round); +} + +/** + * Decrease accuracy of floating-point numbers + * in transforms keeping a specified number of decimals. + * Smart rounds values like 2.349 to 2.35. + * + * @param {Number} fixed number of decimals + * @param {Array} data input data array + * @return {Array} output data array + */ +function smartRound(precision, data) { + for (var i = data.length, tolerance = +Math.pow(.1, precision).toFixed(precision); i--;) { + if (data[i].toFixed(precision) != data[i]) { + var rounded = +data[i].toFixed(precision - 1); + data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance ? + +data[i].toFixed(precision) : + rounded; + } + } + return data; +} diff --git a/node_modules/svgo/plugins/mergePaths.js b/node_modules/svgo/plugins/mergePaths.js new file mode 100644 index 00000000..63cf56e8 --- /dev/null +++ b/node_modules/svgo/plugins/mergePaths.js @@ -0,0 +1,71 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'merges multiple paths in one if possible'; + +exports.params = { + collapseRepeated: true, + leadingZero: true, + negativeExtraSpace: true +}; + +var path2js = require('./_path.js').path2js, + js2path = require('./_path.js').js2path, + intersects = require('./_path.js').intersects; + +/** + * Merge multiple Paths into one. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich, Lev Solntsev + */ +exports.fn = function(item, params) { + + if (!item.isElem() || item.isEmpty()) return; + + var prevContentItem = null, + prevContentItemKeys = null; + + item.content = item.content.filter(function(contentItem) { + + if (prevContentItem && + prevContentItem.isElem('path') && + prevContentItem.isEmpty() && + prevContentItem.hasAttr('d') && + contentItem.isElem('path') && + contentItem.isEmpty() && + contentItem.hasAttr('d') + ) { + + if (!prevContentItemKeys) { + prevContentItemKeys = Object.keys(prevContentItem.attrs); + } + + var contentItemAttrs = Object.keys(contentItem.attrs), + equalData = prevContentItemKeys.length == contentItemAttrs.length && + contentItemAttrs.every(function(key) { + return key == 'd' || + prevContentItem.hasAttr(key) && + prevContentItem.attr(key).value == contentItem.attr(key).value; + }), + prevPathJS = path2js(prevContentItem), + curPathJS = path2js(contentItem); + + if (equalData && !intersects(prevPathJS, curPathJS)) { + js2path(prevContentItem, prevPathJS.concat(curPathJS), params); + return false; + } + } + + prevContentItem = contentItem; + prevContentItemKeys = null; + return true; + + }); + +}; diff --git a/node_modules/svgo/plugins/minifyStyles.js b/node_modules/svgo/plugins/minifyStyles.js new file mode 100644 index 00000000..3977b367 --- /dev/null +++ b/node_modules/svgo/plugins/minifyStyles.js @@ -0,0 +1,45 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.params = { + svgo: {} +}; + +exports.description = 'minifies existing styles in svg'; + +var csso = require('csso'); + +/** + * Minifies styles (<style> element + style attribute) using svgo + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author strarsis <strarsis@gmail.com> + */ +exports.fn = function(item, svgoOptions) { + + if(item.elem) { + if(item.isElem('style') && !item.isEmpty()) { + var styleCss = item.content[0].text || item.content[0].cdata || [], + DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text'; + if(styleCss.length > 0) { + var styleCssMinified = csso.minify(styleCss, svgoOptions); + item.content[0][DATA] = styleCssMinified.css; + } + } + + if(item.hasAttr('style')) { + var itemCss = item.attr('style').value; + if(itemCss.length > 0) { + var itemCssMinified = csso.minifyBlock(itemCss, svgoOptions); + item.attr('style').value = itemCssMinified.css; + } + } + } + + return item; +}; diff --git a/node_modules/svgo/plugins/moveElemsAttrsToGroup.js b/node_modules/svgo/plugins/moveElemsAttrsToGroup.js new file mode 100644 index 00000000..0f3b65c7 --- /dev/null +++ b/node_modules/svgo/plugins/moveElemsAttrsToGroup.js @@ -0,0 +1,126 @@ +'use strict'; + +exports.type = 'perItemReverse'; + +exports.active = true; + +exports.description = 'moves elements attributes to the existing group wrapper'; + +var inheritableAttrs = require('./_collections').inheritableAttrs, + pathElems = require('./_collections.js').pathElems; + +/** + * Collapse content's intersected and inheritable + * attributes to the existing group wrapper. + * + * @example + * <g attr1="val1"> + * <g attr2="val2"> + * text + * </g> + * <circle attr2="val2" attr3="val3"/> + * </g> + * ⬇ + * <g attr1="val1" attr2="val2"> + * <g> + * text + * </g> + * <circle attr3="val3"/> + * </g> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.isElem('g') && !item.isEmpty() && item.content.length > 1) { + + var intersection = {}, + hasTransform = false, + hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'), + intersected = item.content.every(function(inner) { + if (inner.isElem() && inner.hasAttr()) { + // don't mess with possible styles (hack until CSS parsing is implemented) + if (inner.hasAttr('class')) return false; + if (!Object.keys(intersection).length) { + intersection = inner.attrs; + } else { + intersection = intersectInheritableAttrs(intersection, inner.attrs); + + if (!intersection) return false; + } + + return true; + } + }), + allPath = item.content.every(function(inner) { + return inner.isElem(pathElems); + }); + + if (intersected) { + + item.content.forEach(function(g) { + + for (var name in intersection) { + + if (!allPath && !hasClip || name !== 'transform') { + + g.removeAttr(name); + + if (name === 'transform') { + if (!hasTransform) { + if (item.hasAttr('transform')) { + item.attr('transform').value += ' ' + intersection[name].value; + } else { + item.addAttr(intersection[name]); + } + + hasTransform = true; + } + } else { + item.addAttr(intersection[name]); + } + + } + } + + }); + + } + + } + +}; + +/** + * Intersect inheritable attributes. + * + * @param {Object} a first attrs object + * @param {Object} b second attrs object + * + * @return {Object} intersected attrs object + */ +function intersectInheritableAttrs(a, b) { + + var c = {}; + + for (var n in a) { + if ( + b.hasOwnProperty(n) && + inheritableAttrs.indexOf(n) > -1 && + a[n].name === b[n].name && + a[n].value === b[n].value && + a[n].prefix === b[n].prefix && + a[n].local === b[n].local + ) { + c[n] = a[n]; + } + } + + if (!Object.keys(c).length) return false; + + return c; + +} diff --git a/node_modules/svgo/plugins/moveGroupAttrsToElems.js b/node_modules/svgo/plugins/moveGroupAttrsToElems.js new file mode 100644 index 00000000..a966f882 --- /dev/null +++ b/node_modules/svgo/plugins/moveGroupAttrsToElems.js @@ -0,0 +1,63 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'moves some group attributes to the content elements'; + +var collections = require('./_collections.js'), + pathElems = collections.pathElems.concat(['g', 'text']), + referencesProps = collections.referencesProps; + +/** + * Move group attrs to the content elements. + * + * @example + * <g transform="scale(2)"> + * <path transform="rotate(45)" d="M0,0 L10,20"/> + * <path transform="translate(10, 20)" d="M0,10 L20,30"/> + * </g> + * ⬇ + * <g> + * <path transform="scale(2) rotate(45)" d="M0,0 L10,20"/> + * <path transform="scale(2) translate(10, 20)" d="M0,10 L20,30"/> + * </g> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + // move group transform attr to content's pathElems + if ( + item.isElem('g') && + item.hasAttr('transform') && + !item.isEmpty() && + !item.someAttr(function(attr) { + return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url('); + }) && + item.content.every(function(inner) { + return inner.isElem(pathElems) && !inner.hasAttr('id'); + }) + ) { + item.content.forEach(function(inner) { + var attr = item.attr('transform'); + if (inner.hasAttr('transform')) { + inner.attr('transform').value = attr.value + ' ' + inner.attr('transform').value; + } else { + inner.addAttr({ + 'name': attr.name, + 'local': attr.local, + 'prefix': attr.prefix, + 'value': attr.value + }); + } + }); + + item.removeAttr('transform'); + } + +}; diff --git a/node_modules/svgo/plugins/removeAttrs.js b/node_modules/svgo/plugins/removeAttrs.js new file mode 100644 index 00000000..bd2fca62 --- /dev/null +++ b/node_modules/svgo/plugins/removeAttrs.js @@ -0,0 +1,119 @@ +'use strict'; + +var ELEM_SEP = ':'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes specified attributes'; + +exports.params = { + attrs: [] +}; + +/** + * Remove attributes + * + * @param attrs: + * + * format: [ element* : attribute* ] + * + * element : regexp (wrapped into ^...$), single * or omitted > all elements + * attribute : regexp (wrapped into ^...$) + * + * examples: + * + * > basic: remove fill attribute + * --- + * removeAttrs: + * attrs: 'fill' + * + * > remove fill attribute on path element + * --- + * attrs: 'path:fill' + * + * + * > remove all fill and stroke attribute + * --- + * attrs: + * - 'fill' + * - 'stroke' + * + * [is same as] + * + * attrs: '(fill|stroke)' + * + * [is same as] + * + * attrs: '*:(fill|stroke)' + * + * [is same as] + * + * attrs: '.*:(fill|stroke)' + * + * + * > remove all stroke related attributes + * ---- + * attrs: 'stroke.*' + * + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Benny Schudel + */ +exports.fn = function(item, params) { + + // wrap into an array if params is not + if (!Array.isArray(params.attrs)) { + params.attrs = [params.attrs]; + } + + if (item.isElem()) { + + // prepare patterns + var patterns = params.attrs.map(function(pattern) { + + // apply to all elements if specifc element is omitted + if (pattern.indexOf(ELEM_SEP) === -1) { + pattern = ['.*', ELEM_SEP, pattern].join(''); + } + + // create regexps for element and attribute name + return pattern.split(ELEM_SEP) + .map(function(value) { + + // adjust single * to match anything + if (value === '*') { value = '.*'; } + + return new RegExp(['^', value, '$'].join(''), 'i'); + }); + + }); + + // loop patterns + patterns.forEach(function(pattern) { + + // matches element + if (pattern[0].test(item.elem)) { + + // loop attributes + item.eachAttr(function(attr) { + var name = attr.name; + + // matches attribute name + if (pattern[1].test(name)) { + item.removeAttr(name); + } + + }); + + } + + }); + + } + +}; diff --git a/node_modules/svgo/plugins/removeComments.js b/node_modules/svgo/plugins/removeComments.js new file mode 100644 index 00000000..8bfd21b0 --- /dev/null +++ b/node_modules/svgo/plugins/removeComments.js @@ -0,0 +1,27 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes comments'; + +/** + * Remove comments. + * + * @example + * <!-- Generator: Adobe Illustrator 15.0.0, SVG Export + * Plug-In . SVG Version: 6.00 Build 0) --> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.comment && item.comment.charAt(0) !== '!') { + return false; + } + +}; diff --git a/node_modules/svgo/plugins/removeDesc.js b/node_modules/svgo/plugins/removeDesc.js new file mode 100644 index 00000000..e2848c6c --- /dev/null +++ b/node_modules/svgo/plugins/removeDesc.js @@ -0,0 +1,32 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.params = { + removeAny: false +}; + +exports.description = 'removes <desc> (only non-meaningful by default)'; + +var standardDescs = /^Created with/; + +/** + * Removes <desc>. + * Removes only standard editors content or empty elements 'cause it can be used for accessibility. + * Enable parameter 'removeAny' to remove any description. + * + * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Daniel Wabyick + */ +exports.fn = function(item, params) { + + return !item.isElem('desc') || !(params.removeAny || item.isEmpty() || + standardDescs.test(item.content[0].text)); + +}; diff --git a/node_modules/svgo/plugins/removeDimensions.js b/node_modules/svgo/plugins/removeDimensions.js new file mode 100644 index 00000000..b25ff8f7 --- /dev/null +++ b/node_modules/svgo/plugins/removeDimensions.js @@ -0,0 +1,32 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes width and height in presence of viewBox'; + +/** + * Remove width/height attributes when a viewBox attribute is present. + * + * @example + * <svg width="100" height="50" viewBox="0 0 100 50"> + * ↓ + * <svg viewBox="0 0 100 50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if true, with and height will be filtered out + * + * @author Benny Schudel + */ +exports.fn = function(item) { + + if ( + item.isElem('svg') && + item.hasAttr('viewBox') + ) { + item.removeAttr('width'); + item.removeAttr('height'); + } + +}; diff --git a/node_modules/svgo/plugins/removeDoctype.js b/node_modules/svgo/plugins/removeDoctype.js new file mode 100644 index 00000000..32ee4f46 --- /dev/null +++ b/node_modules/svgo/plugins/removeDoctype.js @@ -0,0 +1,40 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes doctype declaration'; + +/** + * Remove DOCTYPE declaration. + * + * "Unfortunately the SVG DTDs are a source of so many + * issues that the SVG WG has decided not to write one + * for the upcoming SVG 1.2 standard. In fact SVG WG + * members are even telling people not to use a DOCTYPE + * declaration in SVG 1.0 and 1.1 documents" + * https://jwatt.org/svg/authoring/#doctype-declaration + * + * @example + * <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + * q"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> + * + * @example + * <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [ + * <!-- an internal subset can be embedded here --> + * ]> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.doctype) { + return false; + } + +}; diff --git a/node_modules/svgo/plugins/removeEditorsNSData.js b/node_modules/svgo/plugins/removeEditorsNSData.js new file mode 100644 index 00000000..9e5c8cd8 --- /dev/null +++ b/node_modules/svgo/plugins/removeEditorsNSData.js @@ -0,0 +1,65 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes editors namespaces, elements and attributes'; + +var editorNamespaces = require('./_collections').editorNamespaces, + prefixes = []; + +exports.params = { + additionalNamespaces: [] +}; + +/** + * Remove editors namespaces, elements and attributes. + * + * @example + * <svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"> + * <sodipodi:namedview/> + * <path sodipodi:nodetypes="cccc"/> + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (Array.isArray(params.additionalNamespaces)) { + editorNamespaces = editorNamespaces.concat(params.additionalNamespaces); + } + + if (item.elem) { + + if (item.isElem('svg')) { + + item.eachAttr(function(attr) { + if (attr.prefix === 'xmlns' && editorNamespaces.indexOf(attr.value) > -1) { + prefixes.push(attr.local); + + // <svg xmlns:sodipodi=""> + item.removeAttr(attr.name); + } + }); + + } + + // <* sodipodi:*=""> + item.eachAttr(function(attr) { + if (prefixes.indexOf(attr.prefix) > -1) { + item.removeAttr(attr.name); + } + }); + + // <sodipodi:*> + if (prefixes.indexOf(item.prefix) > -1) { + return false; + } + + } + +}; diff --git a/node_modules/svgo/plugins/removeElementsByAttr.js b/node_modules/svgo/plugins/removeElementsByAttr.js new file mode 100644 index 00000000..c726f708 --- /dev/null +++ b/node_modules/svgo/plugins/removeElementsByAttr.js @@ -0,0 +1,80 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes arbitrary elements by ID or className (disabled by default)'; + +exports.params = { + id: [], + class: [] +}; + +/** + * Remove arbitrary SVG elements by ID or className. + * + * @param id + * examples: + * + * > single: remove element with ID of `elementID` + * --- + * removeElementsByAttr: + * id: 'elementID' + * + * > list: remove multiple elements by ID + * --- + * removeElementsByAttr: + * id: + * - 'elementID' + * - 'anotherID' + * + * @param class + * examples: + * + * > single: remove all elements with class of `elementClass` + * --- + * removeElementsByAttr: + * class: 'elementClass' + * + * > list: remove all elements with class of `elementClass` or `anotherClass` + * --- + * removeElementsByAttr: + * class: + * - 'elementClass' + * - 'anotherClass' + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Eli Dupuis (@elidupuis) + */ +exports.fn = function(item, params) { + var elemId, elemClass; + + // wrap params in an array if not already + ['id', 'class'].forEach(function(key) { + if (!Array.isArray(params[key])) { + params[key] = [ params[key] ]; + } + }); + + // abort if current item is no an element + if (!item.isElem()) { + return; + } + + // remove element if it's `id` matches configured `id` params + elemId = item.attr('id'); + if (elemId) { + return params.id.indexOf(elemId.value) === -1; + } + + // remove element if it's `class` contains any of the configured `class` params + elemClass = item.attr('class'); + if (elemClass) { + var hasClassRegex = new RegExp(params.class.join('|')); + return !hasClassRegex.test(elemClass.value); + } +}; diff --git a/node_modules/svgo/plugins/removeEmptyAttrs.js b/node_modules/svgo/plugins/removeEmptyAttrs.js new file mode 100644 index 00000000..ae73e6c9 --- /dev/null +++ b/node_modules/svgo/plugins/removeEmptyAttrs.js @@ -0,0 +1,29 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes empty attributes'; + +/** + * Remove attributes with empty values. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.elem) { + + item.eachAttr(function(attr) { + if (attr.value === '') { + item.removeAttr(attr.name); + } + }); + + } + +}; diff --git a/node_modules/svgo/plugins/removeEmptyContainers.js b/node_modules/svgo/plugins/removeEmptyContainers.js new file mode 100644 index 00000000..356a5835 --- /dev/null +++ b/node_modules/svgo/plugins/removeEmptyContainers.js @@ -0,0 +1,32 @@ +'use strict'; + +exports.type = 'perItemReverse'; + +exports.active = true; + +exports.description = 'removes empty container elements'; + +var container = require('./_collections').elemsGroups.container; + +/** + * Remove empty containers. + * + * @see http://www.w3.org/TR/SVG/intro.html#TermContainerElement + * + * @example + * <defs/> + * + * @example + * <g><marker><a/></marker></g> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + return !(item.isElem(container) && !item.isElem('svg') && item.isEmpty() && + (!item.isElem('pattern') || !item.hasAttrLocal('href'))); + +}; diff --git a/node_modules/svgo/plugins/removeEmptyText.js b/node_modules/svgo/plugins/removeEmptyText.js new file mode 100644 index 00000000..049b1819 --- /dev/null +++ b/node_modules/svgo/plugins/removeEmptyText.js @@ -0,0 +1,59 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes empty <text> elements'; + +exports.params = { + text: true, + tspan: true, + tref: true +}; + +/** + * Remove empty Text elements. + * + * @see http://www.w3.org/TR/SVG/text.html + * + * @example + * Remove empty text element: + * <text/> + * + * Remove empty tspan element: + * <tspan/> + * + * Remove tref with empty xlink:href attribute: + * <tref xlink:href=""/> + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + // Remove empty text element + if ( + params.text && + item.isElem('text') && + item.isEmpty() + ) return false; + + // Remove empty tspan element + if ( + params.tspan && + item.isElem('tspan') && + item.isEmpty() + ) return false; + + // Remove tref with empty xlink:href attribute + if ( + params.tref && + item.isElem('tref') && + !item.hasAttrLocal('href') + ) return false; + +}; diff --git a/node_modules/svgo/plugins/removeHiddenElems.js b/node_modules/svgo/plugins/removeHiddenElems.js new file mode 100644 index 00000000..231a2bdf --- /dev/null +++ b/node_modules/svgo/plugins/removeHiddenElems.js @@ -0,0 +1,218 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes hidden elements (zero sized, with absent attributes)'; + +exports.params = { + displayNone: true, + opacity0: true, + circleR0: true, + ellipseRX0: true, + ellipseRY0: true, + rectWidth0: true, + rectHeight0: true, + patternWidth0: true, + patternHeight0: true, + imageWidth0: true, + imageHeight0: true, + pathEmptyD: true, + polylineEmptyPoints: true, + polygonEmptyPoints: true +}; + +var regValidPath = /M\s*(?:[-+]?(?:\d*\.\d+|\d+(?:\.|(?!\.)))([eE][-+]?\d+)?(?!\d)\s*,?\s*){2}\D*\d/i; + +/** + * Remove hidden elements with disabled rendering: + * - display="none" + * - opacity="0" + * - circle with zero radius + * - ellipse with zero x-axis or y-axis radius + * - rectangle with zero width or height + * - pattern with zero width or height + * - image with zero width or height + * - path with empty data + * - polyline with empty points + * - polygon with empty points + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.elem) { + + // display="none" + // + // http://www.w3.org/TR/SVG/painting.html#DisplayProperty + // "A value of display: none indicates that the given element + // and its children shall not be rendered directly" + if ( + params.displayNone && + item.hasAttr('display', 'none') + ) return false; + + // opacity="0" + // + // http://www.w3.org/TR/SVG/masking.html#ObjectAndGroupOpacityProperties + if ( + params.opacity0 && + item.hasAttr('opacity', '0') + ) return false; + + // Circles with zero radius + // + // http://www.w3.org/TR/SVG/shapes.html#CircleElementRAttribute + // "A value of zero disables rendering of the element" + // + // <circle r="0"> + if ( + params.circleR0 && + item.isElem('circle') && + item.isEmpty() && + item.hasAttr('r', '0') + ) return false; + + // Ellipse with zero x-axis radius + // + // http://www.w3.org/TR/SVG/shapes.html#EllipseElementRXAttribute + // "A value of zero disables rendering of the element" + // + // <ellipse rx="0"> + if ( + params.ellipseRX0 && + item.isElem('ellipse') && + item.isEmpty() && + item.hasAttr('rx', '0') + ) return false; + + // Ellipse with zero y-axis radius + // + // http://www.w3.org/TR/SVG/shapes.html#EllipseElementRYAttribute + // "A value of zero disables rendering of the element" + // + // <ellipse ry="0"> + if ( + params.ellipseRY0 && + item.isElem('ellipse') && + item.isEmpty() && + item.hasAttr('ry', '0') + ) return false; + + // Rectangle with zero width + // + // http://www.w3.org/TR/SVG/shapes.html#RectElementWidthAttribute + // "A value of zero disables rendering of the element" + // + // <rect width="0"> + if ( + params.rectWidth0 && + item.isElem('rect') && + item.isEmpty() && + item.hasAttr('width', '0') + ) return false; + + // Rectangle with zero height + // + // http://www.w3.org/TR/SVG/shapes.html#RectElementHeightAttribute + // "A value of zero disables rendering of the element" + // + // <rect height="0"> + if ( + params.rectHeight0 && + params.rectWidth0 && + item.isElem('rect') && + item.isEmpty() && + item.hasAttr('height', '0') + ) return false; + + // Pattern with zero width + // + // http://www.w3.org/TR/SVG/pservers.html#PatternElementWidthAttribute + // "A value of zero disables rendering of the element (i.e., no paint is applied)" + // + // <pattern width="0"> + if ( + params.patternWidth0 && + item.isElem('pattern') && + item.hasAttr('width', '0') + ) return false; + + // Pattern with zero height + // + // http://www.w3.org/TR/SVG/pservers.html#PatternElementHeightAttribute + // "A value of zero disables rendering of the element (i.e., no paint is applied)" + // + // <pattern height="0"> + if ( + params.patternHeight0 && + item.isElem('pattern') && + item.hasAttr('height', '0') + ) return false; + + // Image with zero width + // + // http://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute + // "A value of zero disables rendering of the element" + // + // <image width="0"> + if ( + params.imageWidth0 && + item.isElem('image') && + item.hasAttr('width', '0') + ) return false; + + // Image with zero height + // + // http://www.w3.org/TR/SVG/struct.html#ImageElementHeightAttribute + // "A value of zero disables rendering of the element" + // + // <image height="0"> + if ( + params.imageHeight0 && + item.isElem('image') && + item.hasAttr('height', '0') + ) return false; + + // Path with empty data + // + // http://www.w3.org/TR/SVG/paths.html#DAttribute + // + // <path d=""/> + if ( + params.pathEmptyD && + item.isElem('path') && + (!item.hasAttr('d') || !regValidPath.test(item.attr('d').value)) + ) return false; + + // Polyline with empty points + // + // http://www.w3.org/TR/SVG/shapes.html#PolylineElementPointsAttribute + // + // <polyline points=""> + if ( + params.polylineEmptyPoints && + item.isElem('polyline') && + !item.hasAttr('points') + ) return false; + + // Polygon with empty points + // + // http://www.w3.org/TR/SVG/shapes.html#PolygonElementPointsAttribute + // + // <polygon points=""> + if ( + params.polygonEmptyPoints && + item.isElem('polygon') && + !item.hasAttr('points') + ) return false; + + } + +}; diff --git a/node_modules/svgo/plugins/removeMetadata.js b/node_modules/svgo/plugins/removeMetadata.js new file mode 100644 index 00000000..fa7a5795 --- /dev/null +++ b/node_modules/svgo/plugins/removeMetadata.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes <metadata>'; + +/** + * Remove <metadata>. + * + * http://www.w3.org/TR/SVG/metadata.html + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + return !item.isElem('metadata'); + +}; diff --git a/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js b/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js new file mode 100644 index 00000000..f999d568 --- /dev/null +++ b/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js @@ -0,0 +1,40 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes non-inheritable group’s presentational attributes'; + +var inheritableAttrs = require('./_collections').inheritableAttrs, + attrsGroups = require('./_collections').attrsGroups, + excludedAttrs = ['display', 'opacity']; + +/** + * Remove non-inheritable group's "presentation" attributes. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.isElem('g')) { + + item.eachAttr(function(attr) { + if ( + ~attrsGroups.presentation.indexOf(attr.name) && + ~attrsGroups.graphicalEvent.indexOf(attr.name) && + ~attrsGroups.core.indexOf(attr.name) && + ~attrsGroups.conditionalProcessing.indexOf(attr.name) && + !~excludedAttrs.indexOf(attr.name) && + !~inheritableAttrs.indexOf(attr.name) + ) { + item.removeAttr(attr.name); + } + }); + + } + +}; diff --git a/node_modules/svgo/plugins/removeRasterImages.js b/node_modules/svgo/plugins/removeRasterImages.js new file mode 100644 index 00000000..cbddebe3 --- /dev/null +++ b/node_modules/svgo/plugins/removeRasterImages.js @@ -0,0 +1,28 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes raster images (disabled by default)'; + +/** + * Remove raster images references in <image>. + * + * @see https://bugs.webkit.org/show_bug.cgi?id=63548 + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if ( + item.isElem('image') && + item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/) + ) { + return false; + } + +}; diff --git a/node_modules/svgo/plugins/removeStyleElement.js b/node_modules/svgo/plugins/removeStyleElement.js new file mode 100644 index 00000000..964ce45c --- /dev/null +++ b/node_modules/svgo/plugins/removeStyleElement.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes <style> element (disabled by default)'; + +/** + * Remove <style>. + * + * http://www.w3.org/TR/SVG/styling.html#StyleElement + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Betsy Dupuis + */ +exports.fn = function(item) { + + return !item.isElem('style'); + +}; diff --git a/node_modules/svgo/plugins/removeTitle.js b/node_modules/svgo/plugins/removeTitle.js new file mode 100644 index 00000000..3d077e45 --- /dev/null +++ b/node_modules/svgo/plugins/removeTitle.js @@ -0,0 +1,24 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes <title> (disabled by default)'; + +/** + * Remove <title>. + * Disabled by default cause it may be used for accessibility. + * + * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Igor Kalashnikov + */ +exports.fn = function(item) { + + return !item.isElem('title'); + +}; diff --git a/node_modules/svgo/plugins/removeUnknownsAndDefaults.js b/node_modules/svgo/plugins/removeUnknownsAndDefaults.js new file mode 100644 index 00000000..341b1fd7 --- /dev/null +++ b/node_modules/svgo/plugins/removeUnknownsAndDefaults.js @@ -0,0 +1,143 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes unknown elements content and attributes, removes attrs with default values'; + +exports.params = { + unknownContent: true, + unknownAttrs: true, + defaultAttrs: true, + uselessOverrides: true, + keepDataAttrs: true +}; + +var collections = require('./_collections'), + elems = collections.elems, + attrsGroups = collections.attrsGroups, + elemsGroups = collections.elemsGroups, + attrsGroupsDefaults = collections.attrsGroupsDefaults, + attrsInheritable = collections.inheritableAttrs; + +// collect and extend all references +for (var elem in elems) { + elem = elems[elem]; + + if (elem.attrsGroups) { + elem.attrs = elem.attrs || []; + + elem.attrsGroups.forEach(function(attrsGroupName) { + elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]); + + var groupDefaults = attrsGroupsDefaults[attrsGroupName]; + + if (groupDefaults) { + elem.defaults = elem.defaults || {}; + + for (var attrName in groupDefaults) { + elem.defaults[attrName] = groupDefaults[attrName]; + } + } + }); + + } + + if (elem.contentGroups) { + elem.content = elem.content || []; + + elem.contentGroups.forEach(function(contentGroupName) { + elem.content = elem.content.concat(elemsGroups[contentGroupName]); + }); + } +} + +/** + * Remove unknown elements content and attributes, + * remove attributes with default values. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + // elems w/o namespace prefix + if (item.isElem() && !item.prefix) { + + var elem = item.elem; + + // remove unknown element's content + if ( + params.unknownContent && + !item.isEmpty() && + elems[elem] && // make sure we know of this element before checking its children + elem !== 'foreignObject' // Don't check foreignObject + ) { + item.content.forEach(function(content, i) { + if ( + content.isElem() && + !content.prefix && + ( + ( + elems[elem].content && // Do we have a record of its permitted content? + elems[elem].content.indexOf(content.elem) === -1 + ) || + ( + !elems[elem].content && // we dont know about its permitted content + !elems[content.elem] // check that we know about the element at all + ) + ) + ) { + item.content.splice(i, 1); + } + }); + } + + // remove element's unknown attrs and attrs with default values + if (elems[elem] && elems[elem].attrs) { + + item.eachAttr(function(attr) { + + if ( + attr.name !== 'xmlns' && + (attr.prefix === 'xml' || !attr.prefix) && + (!params.keepDataAttrs || attr.name.indexOf('data-') != 0) + ) { + if ( + // unknown attrs + ( + params.unknownAttrs && + elems[elem].attrs.indexOf(attr.name) === -1 + ) || + // attrs with default values + ( + params.defaultAttrs && + elems[elem].defaults && + elems[elem].defaults[attr.name] === attr.value && ( + attrsInheritable.indexOf(attr.name) < 0 || + !item.parentNode.computedAttr(attr.name) + ) + ) || + // useless overrides + ( + params.uselessOverrides && + attr.name !== 'transform' && + attrsInheritable.indexOf(attr.name) > -1 && + item.parentNode.computedAttr(attr.name, attr.value) + ) + ) { + item.removeAttr(attr.name); + } + } + + }); + + } + + } + +}; diff --git a/node_modules/svgo/plugins/removeUnusedNS.js b/node_modules/svgo/plugins/removeUnusedNS.js new file mode 100644 index 00000000..c4787915 --- /dev/null +++ b/node_modules/svgo/plugins/removeUnusedNS.js @@ -0,0 +1,107 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'removes unused namespaces declaration'; + +/** + * Remove unused namespaces declaration. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(data) { + + var svgElem, + xmlnsCollection = []; + + /** + * Remove namespace from collection. + * + * @param {String} ns namescape name + */ + function removeNSfromCollection(ns) { + + var pos = xmlnsCollection.indexOf(ns); + + // if found - remove ns from the namespaces collection + if (pos > -1) { + xmlnsCollection.splice(pos, 1); + } + + } + + /** + * Bananas! + * + * @param {Array} items input items + * + * @return {Array} output items + */ + function monkeys(items) { + + var i = 0, + length = items.content.length; + + while(i < length) { + + var item = items.content[i]; + + if (item.isElem('svg')) { + + item.eachAttr(function(attr) { + // collect namespaces + if (attr.prefix === 'xmlns' && attr.local) { + xmlnsCollection.push(attr.local); + } + }); + + // if svg element has ns-attr + if (xmlnsCollection.length) { + // save svg element + svgElem = item; + } + + } else if (xmlnsCollection.length) { + + // check item for the ns-attrs + if (item.prefix) { + removeNSfromCollection(item.prefix); + } + + // check each attr for the ns-attrs + item.eachAttr(function(attr) { + removeNSfromCollection(attr.prefix); + }); + + } + + // if nothing is found - go deeper + if (xmlnsCollection.length && item.content) { + monkeys(item); + } + + i++; + + } + + return items; + + } + + data = monkeys(data); + + // remove svg element ns-attributes if they are not used even once + if (xmlnsCollection.length) { + xmlnsCollection.forEach(function(name) { + svgElem.removeAttr('xmlns:' + name); + }); + } + + return data; + +}; diff --git a/node_modules/svgo/plugins/removeUselessDefs.js b/node_modules/svgo/plugins/removeUselessDefs.js new file mode 100644 index 00000000..b8c97a52 --- /dev/null +++ b/node_modules/svgo/plugins/removeUselessDefs.js @@ -0,0 +1,51 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes elements in <defs> without id'; + +var nonRendering = require('./_collections').elemsGroups.nonRendering, + defs; + +/** + * Removes content of defs and properties that aren't rendered directly without ids. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Lev Solntsev + */ +exports.fn = function(item) { + + if (item.isElem('defs')) { + + defs = item; + item.content = (item.content || []).reduce(getUsefulItems, []); + + if (item.isEmpty()) return false; + + } else if (item.isElem(nonRendering) && !item.hasAttr('id')) { + + return false; + + } + +}; + +function getUsefulItems(usefulItems, item) { + + if (item.hasAttr('id') || item.isElem('style')) { + + usefulItems.push(item); + item.parentNode = defs; + + } else if (!item.isEmpty()) { + + item.content.reduce(getUsefulItems, usefulItems); + + } + + return usefulItems; +} diff --git a/node_modules/svgo/plugins/removeUselessStrokeAndFill.js b/node_modules/svgo/plugins/removeUselessStrokeAndFill.js new file mode 100644 index 00000000..47090eb8 --- /dev/null +++ b/node_modules/svgo/plugins/removeUselessStrokeAndFill.js @@ -0,0 +1,92 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes useless stroke and fill attributes'; + +exports.params = { + stroke: true, + fill: true +}; + +var shape = require('./_collections').elemsGroups.shape, + regStrokeProps = /^stroke/, + regFillProps = /^fill-/, + styleOrScript = ['style', 'script'], + hasStyleOrScript = false; + +/** + * Remove useless stroke and fill attrs. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem(styleOrScript)) { + hasStyleOrScript = true; + } + + if (!hasStyleOrScript && item.isElem(shape) && !item.computedAttr('id')) { + + var stroke = params.stroke && item.computedAttr('stroke'), + fill = params.fill && !item.computedAttr('fill', 'none'); + + // remove stroke* + if ( + params.stroke && + (!stroke || + stroke == 'none' || + item.computedAttr('stroke-opacity', '0') || + item.computedAttr('stroke-width', '0') + ) + ) { + var parentStroke = item.parentNode.computedAttr('stroke'), + declineStroke = parentStroke && parentStroke != 'none'; + + item.eachAttr(function(attr) { + if (regStrokeProps.test(attr.name)) { + item.removeAttr(attr.name); + } + }); + + if (declineStroke) item.addAttr({ + name: 'stroke', + value: 'none', + prefix: '', + local: 'stroke' + }); + } + + // remove fill* + if ( + params.fill && + (!fill || item.computedAttr('fill-opacity', '0')) + ) { + item.eachAttr(function(attr) { + if (regFillProps.test(attr.name)) { + item.removeAttr(attr.name); + } + }); + + if (fill) { + if (item.hasAttr('fill')) + item.attr('fill').value = 'none'; + else + item.addAttr({ + name: 'fill', + value: 'none', + prefix: '', + local: 'fill' + }); + } + } + + } + +}; diff --git a/node_modules/svgo/plugins/removeViewBox.js b/node_modules/svgo/plugins/removeViewBox.js new file mode 100644 index 00000000..33595656 --- /dev/null +++ b/node_modules/svgo/plugins/removeViewBox.js @@ -0,0 +1,49 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes viewBox attribute when possible (disabled by default)'; + +var regViewBox = /^0\s0\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)$/, + viewBoxElems = ['svg', 'pattern']; + +/** + * Remove viewBox attr which coincides with a width/height box. + * + * @see http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute + * + * @example + * <svg width="100" height="50" viewBox="0 0 100 50"> + * ⬇ + * <svg width="100" height="50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if ( + item.isElem(viewBoxElems) && + item.hasAttr('viewBox') && + item.hasAttr('width') && + item.hasAttr('height') + ) { + + var match = item.attr('viewBox').value.match(regViewBox); + + if (match) { + if ( + item.attr('width').value === match[1] && + item.attr('height').value === match[3] + ) { + item.removeAttr('viewBox'); + } + } + + } + +}; diff --git a/node_modules/svgo/plugins/removeXMLNS.js b/node_modules/svgo/plugins/removeXMLNS.js new file mode 100644 index 00000000..afda99d3 --- /dev/null +++ b/node_modules/svgo/plugins/removeXMLNS.js @@ -0,0 +1,28 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes xmlns attribute (for inline svg, disabled by default)'; + +/** + * Remove the xmlns attribute when present. + * + * @example + * <svg viewBox="0 0 100 50" xmlns="http://www.w3.org/2000/svg"> + * ↓ + * <svg viewBox="0 0 100 50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if true, xmlns will be filtered out + * + * @author Ricardo Tomasi + */ +exports.fn = function(item) { + + if (item.isElem('svg') && item.hasAttr('xmlns')) { + item.removeAttr('xmlns'); + } + +};
\ No newline at end of file diff --git a/node_modules/svgo/plugins/removeXMLProcInst.js b/node_modules/svgo/plugins/removeXMLProcInst.js new file mode 100644 index 00000000..afd425d5 --- /dev/null +++ b/node_modules/svgo/plugins/removeXMLProcInst.js @@ -0,0 +1,24 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes XML processing instructions'; + +/** + * Remove XML Processing Instruction. + * + * @example + * <?xml version="1.0" encoding="utf-8"?> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + return !(item.processinginstruction && item.processinginstruction.name === 'xml'); + +}; diff --git a/node_modules/svgo/plugins/sortAttrs.js b/node_modules/svgo/plugins/sortAttrs.js new file mode 100644 index 00000000..221a4bf5 --- /dev/null +++ b/node_modules/svgo/plugins/sortAttrs.js @@ -0,0 +1,81 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'sorts element attributes (disabled by default)'; + +exports.params = { + order: [ + 'id', + 'width', 'height', + 'x', 'x1', 'x2', + 'y', 'y1', 'y2', + 'cx', 'cy', 'r', + 'fill', 'stroke', 'marker', + 'd', 'points' + ] +}; + +/** + * Sort element attributes for epic readability. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * + * @author Nikolay Frantsev + */ +exports.fn = function(item, params) { + + var attrs = [], + sorted = {}, + orderlen = params.order.length + 1; + + if (item.elem) { + + item.eachAttr(function(attr) { + attrs.push(attr); + }); + + attrs.sort(function(a, b) { + if (a.prefix != b.prefix) { + // xmlns attributes implicitly have the prefix xmlns + if (a.prefix == 'xmlns') + return -1; + if (b.prefix == 'xmlns') + return 1; + return a.prefix < b.prefix ? -1 : 1; + } + + var aindex = orderlen; + var bindex = orderlen; + + for (var i = 0; i < params.order.length; i++) { + if (a.name == params.order[i]) { + aindex = i; + } else if (a.name.indexOf(params.order[i] + '-') === 0) { + aindex = i + .5; + } + if (b.name == params.order[i]) { + bindex = i; + } else if (b.name.indexOf(params.order[i] + '-') === 0) { + bindex = i + .5; + } + } + + if (aindex != bindex) { + return aindex - bindex; + } + return a.name < b.name ? -1 : 1; + }); + + attrs.forEach(function (attr) { + sorted[attr.name] = attr; + }); + + item.attrs = sorted; + + } + +}; diff --git a/node_modules/svgo/plugins/transformsWithOnePath.js b/node_modules/svgo/plugins/transformsWithOnePath.js new file mode 100644 index 00000000..f4dec7e6 --- /dev/null +++ b/node_modules/svgo/plugins/transformsWithOnePath.js @@ -0,0 +1,327 @@ +'use strict'; + +/* + * Thanks to http://fontello.com project for sponsoring this plugin + */ + +exports.type = 'full'; + +exports.active = false; + +exports.description = 'performs a set of operations on SVG with one path inside (disabled by default)'; + +exports.params = { + // width and height to resize SVG and rescale inner Path + width: false, + height: false, + + // scale inner Path without resizing SVG + scale: false, + + // shiftX/Y inner Path + shiftX: false, + shiftY: false, + + // crop SVG width along the real width of inner Path + hcrop: false, + + // vertical center inner Path inside SVG height + vcenter: false, + + // stringify params + floatPrecision: 3, + leadingZero: true, + negativeExtraSpace: true +}; + +var _path = require('./_path.js'), + relative2absolute = _path.relative2absolute, + computeCubicBoundingBox = _path.computeCubicBoundingBox, + computeQuadraticBoundingBox = _path.computeQuadraticBoundingBox, + applyTransforms = _path.applyTransforms, + js2path = _path.js2path, + path2js = _path.path2js, + EXTEND = require('whet.extend'); + +exports.fn = function(data, params) { + + data.content.forEach(function(item) { + + // only for SVG with one Path inside + if (item.isElem('svg') && + item.content.length === 1 && + item.content[0].isElem('path') + ) { + + var svgElem = item, + pathElem = svgElem.content[0], + // get absoluted Path data + path = relative2absolute(EXTEND(true, [], path2js(pathElem))), + xs = [], + ys = [], + cubicСontrolPoint = [0, 0], + quadraticСontrolPoint = [0, 0], + lastPoint = [0, 0], + cubicBoundingBox, + quadraticBoundingBox, + i, + segment; + + path.forEach(function(pathItem) { + + // ML + if ('ML'.indexOf(pathItem.instruction) > -1) { + + for (i = 0; i < pathItem.data.length; i++) { + if (i % 2 === 0) { + xs.push(pathItem.data[i]); + } else { + ys.push(pathItem.data[i]); + } + } + + lastPoint = cubicСontrolPoint = quadraticСontrolPoint = pathItem.data.slice(-2); + + // H + } else if (pathItem.instruction === 'H') { + + pathItem.data.forEach(function(d) { + xs.push(d); + }); + + lastPoint[0] = cubicСontrolPoint[0] = quadraticСontrolPoint[0] = pathItem.data[pathItem.data.length - 2]; + + // V + } else if (pathItem.instruction === 'V') { + + pathItem.data.forEach(function(d) { + ys.push(d); + }); + + lastPoint[1] = cubicСontrolPoint[1] = quadraticСontrolPoint[1] = pathItem.data[pathItem.data.length - 1]; + + // C + } else if (pathItem.instruction === 'C') { + + for (i = 0; i < pathItem.data.length; i += 6) { + + segment = pathItem.data.slice(i, i + 6); + + cubicBoundingBox = computeCubicBoundingBox.apply(this, lastPoint.concat(segment)); + + xs.push(cubicBoundingBox.minx); + xs.push(cubicBoundingBox.maxx); + + ys.push(cubicBoundingBox.miny); + ys.push(cubicBoundingBox.maxy); + + // reflected control point for the next possible S + cubicСontrolPoint = [ + 2 * segment[4] - segment[2], + 2 * segment[5] - segment[3] + ]; + + lastPoint = segment.slice(-2); + + } + + // S + } else if (pathItem.instruction === 'S') { + + for (i = 0; i < pathItem.data.length; i += 4) { + + segment = pathItem.data.slice(i, i + 4); + + cubicBoundingBox = computeCubicBoundingBox.apply(this, lastPoint.concat(cubicСontrolPoint).concat(segment)); + + xs.push(cubicBoundingBox.minx); + xs.push(cubicBoundingBox.maxx); + + ys.push(cubicBoundingBox.miny); + ys.push(cubicBoundingBox.maxy); + + // reflected control point for the next possible S + cubicСontrolPoint = [ + 2 * segment[2] - cubicСontrolPoint[0], + 2 * segment[3] - cubicСontrolPoint[1], + ]; + + lastPoint = segment.slice(-2); + + } + + // Q + } else if (pathItem.instruction === 'Q') { + + for (i = 0; i < pathItem.data.length; i += 4) { + + segment = pathItem.data.slice(i, i + 4); + + quadraticBoundingBox = computeQuadraticBoundingBox.apply(this, lastPoint.concat(segment)); + + xs.push(quadraticBoundingBox.minx); + xs.push(quadraticBoundingBox.maxx); + + ys.push(quadraticBoundingBox.miny); + ys.push(quadraticBoundingBox.maxy); + + // reflected control point for the next possible T + quadraticСontrolPoint = [ + 2 * segment[2] - segment[0], + 2 * segment[3] - segment[1] + ]; + + lastPoint = segment.slice(-2); + + } + + // S + } else if (pathItem.instruction === 'T') { + + for (i = 0; i < pathItem.data.length; i += 2) { + + segment = pathItem.data.slice(i, i + 2); + + quadraticBoundingBox = computeQuadraticBoundingBox.apply(this, lastPoint.concat(quadraticСontrolPoint).concat(segment)); + + xs.push(quadraticBoundingBox.minx); + xs.push(quadraticBoundingBox.maxx); + + ys.push(quadraticBoundingBox.miny); + ys.push(quadraticBoundingBox.maxy); + + // reflected control point for the next possible T + quadraticСontrolPoint = [ + 2 * segment[0] - quadraticСontrolPoint[0], + 2 * segment[1] - quadraticСontrolPoint[1] + ]; + + lastPoint = segment.slice(-2); + + } + + } + + }); + + var xmin = Math.min.apply(this, xs).toFixed(params.floatPrecision), + xmax = Math.max.apply(this, xs).toFixed(params.floatPrecision), + ymin = Math.min.apply(this, ys).toFixed(params.floatPrecision), + ymax = Math.max.apply(this, ys).toFixed(params.floatPrecision), + svgWidth = +svgElem.attr('width').value, + svgHeight = +svgElem.attr('height').value, + realWidth = Math.round(xmax - xmin), + realHeight = Math.round(ymax - ymin), + transform = '', + scale; + + // width & height + if (params.width && params.height) { + + scale = Math.min(params.width / svgWidth, params.height / svgHeight); + + realWidth = realWidth * scale; + realHeight = realHeight * scale; + + svgWidth = svgElem.attr('width').value = params.width; + svgHeight = svgElem.attr('height').value = params.height; + + transform += ' scale(' + scale + ')'; + + // width + } else if (params.width && !params.height) { + + scale = params.width / svgWidth; + + realWidth = realWidth * scale; + realHeight = realHeight * scale; + + svgWidth = svgElem.attr('width').value = params.width; + svgHeight = svgElem.attr('height').value = svgHeight * scale; + + transform += ' scale(' + scale + ')'; + + // height + } else if (params.height && !params.width) { + + scale = params.height / svgHeight; + + realWidth = realWidth * scale; + realHeight = realHeight * scale; + + svgWidth = svgElem.attr('width').value = svgWidth * scale; + svgHeight = svgElem.attr('height').value = params.height; + + transform += ' scale(' + scale + ')'; + + } + + // shiftX + if (params.shiftX) { + transform += ' translate(' + realWidth * params.shiftX + ', 0)'; + } + + // shiftY + if (params.shiftY) { + transform += ' translate(0, ' + realHeight * params.shiftY + ')'; + } + + // scale + if (params.scale) { + scale = params.scale; + + var shiftX = svgWidth / 2, + shiftY = svgHeight / 2; + + realWidth = realWidth * scale; + realHeight = realHeight * scale; + + if (params.shiftX || params.shiftY) { + transform += ' scale(' + scale + ')'; + } else { + transform += ' translate(' + shiftX + ' ' + shiftY + ') scale(' + scale + ') translate(-' + shiftX + ' -' + shiftY + ')'; + } + } + + // hcrop + if (params.hcrop) { + transform += ' translate(' + (-xmin) + ' 0)'; + + svgElem.attr('width').value = realWidth; + } + + // vcenter + if (params.vcenter) { + transform += ' translate(0 ' + (((svgHeight - realHeight) / 2) - ymin) + ')'; + } + + if (transform) { + pathElem.addAttr({ + name: 'transform', + prefix: '', + local: 'transform', + value: transform + }); + + path = applyTransforms(pathElem, pathElem.pathJS, true, params.floatPrecision); + + // transformed data rounding + path.forEach(function(pathItem) { + if (pathItem.data) { + pathItem.data = pathItem.data.map(function(num) { + return +num.toFixed(params.floatPrecision); + }); + } + }); + + // save new + js2path(pathElem, path, params); + } + + } + + }); + + return data; + +}; |
