svg-parser.umd.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = global || self, factory(global.svgParser = {}));
  5. }(this, (function (exports) { 'use strict';
  6. function getLocator(source, options) {
  7. if (options === void 0) { options = {}; }
  8. var offsetLine = options.offsetLine || 0;
  9. var offsetColumn = options.offsetColumn || 0;
  10. var originalLines = source.split('\n');
  11. var start = 0;
  12. var lineRanges = originalLines.map(function (line, i) {
  13. var end = start + line.length + 1;
  14. var range = { start: start, end: end, line: i };
  15. start = end;
  16. return range;
  17. });
  18. var i = 0;
  19. function rangeContains(range, index) {
  20. return range.start <= index && index < range.end;
  21. }
  22. function getLocation(range, index) {
  23. return { line: offsetLine + range.line, column: offsetColumn + index - range.start, character: index };
  24. }
  25. function locate(search, startIndex) {
  26. if (typeof search === 'string') {
  27. search = source.indexOf(search, startIndex || 0);
  28. }
  29. var range = lineRanges[i];
  30. var d = search >= range.end ? 1 : -1;
  31. while (range) {
  32. if (rangeContains(range, search))
  33. return getLocation(range, search);
  34. i += d;
  35. range = lineRanges[i];
  36. }
  37. }
  38. return locate;
  39. }
  40. function locate(source, search, options) {
  41. if (typeof options === 'number') {
  42. throw new Error('locate takes a { startIndex, offsetLine, offsetColumn } object as the third argument');
  43. }
  44. return getLocator(source, options)(search, options && options.startIndex);
  45. }
  46. var validNameCharacters = /[a-zA-Z0-9:_-]/;
  47. var whitespace = /[\s\t\r\n]/;
  48. var quotemark = /['"]/;
  49. function repeat(str, i) {
  50. var result = '';
  51. while (i--) { result += str; }
  52. return result;
  53. }
  54. function parse(source) {
  55. var header = '';
  56. var stack = [];
  57. var state = metadata;
  58. var currentElement = null;
  59. var root = null;
  60. function error(message) {
  61. var ref = locate(source, i);
  62. var line = ref.line;
  63. var column = ref.column;
  64. var before = source.slice(0, i);
  65. var beforeLine = /(^|\n).*$/.exec(before)[0].replace(/\t/g, ' ');
  66. var after = source.slice(i);
  67. var afterLine = /.*(\n|$)/.exec(after)[0];
  68. var snippet = "" + beforeLine + afterLine + "\n" + (repeat(' ', beforeLine.length)) + "^";
  69. throw new Error(
  70. (message + " (" + line + ":" + column + "). If this is valid SVG, it's probably a bug in svg-parser. Please raise an issue at https://github.com/Rich-Harris/svg-parser/issues – thanks!\n\n" + snippet)
  71. );
  72. }
  73. function metadata() {
  74. while ((i < source.length && source[i] !== '<') || !validNameCharacters.test(source[i + 1])) {
  75. header += source[i++];
  76. }
  77. return neutral();
  78. }
  79. function neutral() {
  80. var text = '';
  81. while (i < source.length && source[i] !== '<') { text += source[i++]; }
  82. if (/\S/.test(text)) {
  83. currentElement.children.push({ type: 'text', value: text });
  84. }
  85. if (source[i] === '<') {
  86. return tag;
  87. }
  88. return neutral;
  89. }
  90. function tag() {
  91. var char = source[i];
  92. if (char === '?') { return neutral; } // <?xml...
  93. if (char === '!') {
  94. if (source.slice(i + 1, i + 3) === '--') { return comment; }
  95. if (source.slice(i + 1, i + 8) === '[CDATA[') { return cdata; }
  96. if (/doctype/i.test(source.slice(i + 1, i + 8))) { return neutral; }
  97. }
  98. if (char === '/') { return closingTag; }
  99. var tagName = getName();
  100. var element = {
  101. type: 'element',
  102. tagName: tagName,
  103. properties: {},
  104. children: []
  105. };
  106. if (currentElement) {
  107. currentElement.children.push(element);
  108. } else {
  109. root = element;
  110. }
  111. var attribute;
  112. while (i < source.length && (attribute = getAttribute())) {
  113. element.properties[attribute.name] = attribute.value;
  114. }
  115. var selfClosing = false;
  116. if (source[i] === '/') {
  117. i += 1;
  118. selfClosing = true;
  119. }
  120. if (source[i] !== '>') {
  121. error('Expected >');
  122. }
  123. if (!selfClosing) {
  124. currentElement = element;
  125. stack.push(element);
  126. }
  127. return neutral;
  128. }
  129. function comment() {
  130. var index = source.indexOf('-->', i);
  131. if (!~index) { error('expected -->'); }
  132. i = index + 2;
  133. return neutral;
  134. }
  135. function cdata() {
  136. var index = source.indexOf(']]>', i);
  137. if (!~index) { error('expected ]]>'); }
  138. currentElement.children.push(source.slice(i + 7, index));
  139. i = index + 2;
  140. return neutral;
  141. }
  142. function closingTag() {
  143. var tagName = getName();
  144. if (!tagName) { error('Expected tag name'); }
  145. if (tagName !== currentElement.tagName) {
  146. error(("Expected closing tag </" + tagName + "> to match opening tag <" + (currentElement.tagName) + ">"));
  147. }
  148. allowSpaces();
  149. if (source[i] !== '>') {
  150. error('Expected >');
  151. }
  152. stack.pop();
  153. currentElement = stack[stack.length - 1];
  154. return neutral;
  155. }
  156. function getName() {
  157. var name = '';
  158. while (i < source.length && validNameCharacters.test(source[i])) { name += source[i++]; }
  159. return name;
  160. }
  161. function getAttribute() {
  162. if (!whitespace.test(source[i])) { return null; }
  163. allowSpaces();
  164. var name = getName();
  165. if (!name) { return null; }
  166. var value = true;
  167. allowSpaces();
  168. if (source[i] === '=') {
  169. i += 1;
  170. allowSpaces();
  171. value = getAttributeValue();
  172. if (!isNaN(value) && value.trim() !== '') { value = +value; } // TODO whitelist numeric attributes?
  173. }
  174. return { name: name, value: value };
  175. }
  176. function getAttributeValue() {
  177. return quotemark.test(source[i]) ? getQuotedAttributeValue() : getUnquotedAttributeValue();
  178. }
  179. function getUnquotedAttributeValue() {
  180. var value = '';
  181. do {
  182. var char = source[i];
  183. if (char === ' ' || char === '>' || char === '/') {
  184. return value;
  185. }
  186. value += char;
  187. i += 1;
  188. } while (i < source.length);
  189. return value;
  190. }
  191. function getQuotedAttributeValue() {
  192. var quotemark = source[i++];
  193. var value = '';
  194. var escaped = false;
  195. while (i < source.length) {
  196. var char = source[i++];
  197. if (char === quotemark && !escaped) {
  198. return value;
  199. }
  200. if (char === '\\' && !escaped) {
  201. escaped = true;
  202. }
  203. value += escaped ? ("\\" + char) : char;
  204. escaped = false;
  205. }
  206. }
  207. function allowSpaces() {
  208. while (i < source.length && whitespace.test(source[i])) { i += 1; }
  209. }
  210. var i = metadata.length;
  211. while (i < source.length) {
  212. if (!state) { error('Unexpected character'); }
  213. state = state();
  214. i += 1;
  215. }
  216. if (state !== neutral) {
  217. error('Unexpected end of input');
  218. }
  219. if (root.tagName === 'svg') { root.metadata = header; }
  220. return {
  221. type: 'root',
  222. children: [root]
  223. };
  224. }
  225. exports.parse = parse;
  226. Object.defineProperty(exports, '__esModule', { value: true });
  227. })));
  228. //# sourceMappingURL=svg-parser.umd.js.map