/frontend/node_modules/css-tree/dist/csstree.js

https://gitlab.com/sogeta_albazi/books-and-movies · JavaScript · 1656 lines · 1135 code · 321 blank · 200 comment · 202 complexity · 75fc2642ceda38e0a4c622e933bd8d64 MD5 · raw file

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = global || self, global.csstree = factory());
  5. }(this, function () { 'use strict';
  6. //
  7. // list
  8. // ┌──────┐
  9. // ┌──────────────┼─head │
  10. // │ │ tail─┼──────────────┐
  11. // │ └──────┘ │
  12. // ▼ ▼
  13. // item item item item
  14. // ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
  15. // null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │
  16. // │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null
  17. // ├──────┤ ├──────┤ ├──────┤ ├──────┤
  18. // │ data │ │ data │ │ data │ │ data │
  19. // └──────┘ └──────┘ └──────┘ └──────┘
  20. //
  21. function createItem(data) {
  22. return {
  23. prev: null,
  24. next: null,
  25. data: data
  26. };
  27. }
  28. function allocateCursor(node, prev, next) {
  29. var cursor;
  30. if (cursors !== null) {
  31. cursor = cursors;
  32. cursors = cursors.cursor;
  33. cursor.prev = prev;
  34. cursor.next = next;
  35. cursor.cursor = node.cursor;
  36. } else {
  37. cursor = {
  38. prev: prev,
  39. next: next,
  40. cursor: node.cursor
  41. };
  42. }
  43. node.cursor = cursor;
  44. return cursor;
  45. }
  46. function releaseCursor(node) {
  47. var cursor = node.cursor;
  48. node.cursor = cursor.cursor;
  49. cursor.prev = null;
  50. cursor.next = null;
  51. cursor.cursor = cursors;
  52. cursors = cursor;
  53. }
  54. var cursors = null;
  55. var List = function() {
  56. this.cursor = null;
  57. this.head = null;
  58. this.tail = null;
  59. };
  60. List.createItem = createItem;
  61. List.prototype.createItem = createItem;
  62. List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) {
  63. var cursor = this.cursor;
  64. while (cursor !== null) {
  65. if (cursor.prev === prevOld) {
  66. cursor.prev = prevNew;
  67. }
  68. if (cursor.next === nextOld) {
  69. cursor.next = nextNew;
  70. }
  71. cursor = cursor.cursor;
  72. }
  73. };
  74. List.prototype.getSize = function() {
  75. var size = 0;
  76. var cursor = this.head;
  77. while (cursor) {
  78. size++;
  79. cursor = cursor.next;
  80. }
  81. return size;
  82. };
  83. List.prototype.fromArray = function(array) {
  84. var cursor = null;
  85. this.head = null;
  86. for (var i = 0; i < array.length; i++) {
  87. var item = createItem(array[i]);
  88. if (cursor !== null) {
  89. cursor.next = item;
  90. } else {
  91. this.head = item;
  92. }
  93. item.prev = cursor;
  94. cursor = item;
  95. }
  96. this.tail = cursor;
  97. return this;
  98. };
  99. List.prototype.toArray = function() {
  100. var cursor = this.head;
  101. var result = [];
  102. while (cursor) {
  103. result.push(cursor.data);
  104. cursor = cursor.next;
  105. }
  106. return result;
  107. };
  108. List.prototype.toJSON = List.prototype.toArray;
  109. List.prototype.isEmpty = function() {
  110. return this.head === null;
  111. };
  112. List.prototype.first = function() {
  113. return this.head && this.head.data;
  114. };
  115. List.prototype.last = function() {
  116. return this.tail && this.tail.data;
  117. };
  118. List.prototype.each = function(fn, context) {
  119. var item;
  120. if (context === undefined) {
  121. context = this;
  122. }
  123. // push cursor
  124. var cursor = allocateCursor(this, null, this.head);
  125. while (cursor.next !== null) {
  126. item = cursor.next;
  127. cursor.next = item.next;
  128. fn.call(context, item.data, item, this);
  129. }
  130. // pop cursor
  131. releaseCursor(this);
  132. };
  133. List.prototype.forEach = List.prototype.each;
  134. List.prototype.eachRight = function(fn, context) {
  135. var item;
  136. if (context === undefined) {
  137. context = this;
  138. }
  139. // push cursor
  140. var cursor = allocateCursor(this, this.tail, null);
  141. while (cursor.prev !== null) {
  142. item = cursor.prev;
  143. cursor.prev = item.prev;
  144. fn.call(context, item.data, item, this);
  145. }
  146. // pop cursor
  147. releaseCursor(this);
  148. };
  149. List.prototype.forEachRight = List.prototype.eachRight;
  150. List.prototype.nextUntil = function(start, fn, context) {
  151. if (start === null) {
  152. return;
  153. }
  154. var item;
  155. if (context === undefined) {
  156. context = this;
  157. }
  158. // push cursor
  159. var cursor = allocateCursor(this, null, start);
  160. while (cursor.next !== null) {
  161. item = cursor.next;
  162. cursor.next = item.next;
  163. if (fn.call(context, item.data, item, this)) {
  164. break;
  165. }
  166. }
  167. // pop cursor
  168. releaseCursor(this);
  169. };
  170. List.prototype.prevUntil = function(start, fn, context) {
  171. if (start === null) {
  172. return;
  173. }
  174. var item;
  175. if (context === undefined) {
  176. context = this;
  177. }
  178. // push cursor
  179. var cursor = allocateCursor(this, start, null);
  180. while (cursor.prev !== null) {
  181. item = cursor.prev;
  182. cursor.prev = item.prev;
  183. if (fn.call(context, item.data, item, this)) {
  184. break;
  185. }
  186. }
  187. // pop cursor
  188. releaseCursor(this);
  189. };
  190. List.prototype.some = function(fn, context) {
  191. var cursor = this.head;
  192. if (context === undefined) {
  193. context = this;
  194. }
  195. while (cursor !== null) {
  196. if (fn.call(context, cursor.data, cursor, this)) {
  197. return true;
  198. }
  199. cursor = cursor.next;
  200. }
  201. return false;
  202. };
  203. List.prototype.map = function(fn, context) {
  204. var result = new List();
  205. var cursor = this.head;
  206. if (context === undefined) {
  207. context = this;
  208. }
  209. while (cursor !== null) {
  210. result.appendData(fn.call(context, cursor.data, cursor, this));
  211. cursor = cursor.next;
  212. }
  213. return result;
  214. };
  215. List.prototype.filter = function(fn, context) {
  216. var result = new List();
  217. var cursor = this.head;
  218. if (context === undefined) {
  219. context = this;
  220. }
  221. while (cursor !== null) {
  222. if (fn.call(context, cursor.data, cursor, this)) {
  223. result.appendData(cursor.data);
  224. }
  225. cursor = cursor.next;
  226. }
  227. return result;
  228. };
  229. List.prototype.clear = function() {
  230. this.head = null;
  231. this.tail = null;
  232. };
  233. List.prototype.copy = function() {
  234. var result = new List();
  235. var cursor = this.head;
  236. while (cursor !== null) {
  237. result.insert(createItem(cursor.data));
  238. cursor = cursor.next;
  239. }
  240. return result;
  241. };
  242. List.prototype.prepend = function(item) {
  243. // head
  244. // ^
  245. // item
  246. this.updateCursors(null, item, this.head, item);
  247. // insert to the beginning of the list
  248. if (this.head !== null) {
  249. // new item <- first item
  250. this.head.prev = item;
  251. // new item -> first item
  252. item.next = this.head;
  253. } else {
  254. // if list has no head, then it also has no tail
  255. // in this case tail points to the new item
  256. this.tail = item;
  257. }
  258. // head always points to new item
  259. this.head = item;
  260. return this;
  261. };
  262. List.prototype.prependData = function(data) {
  263. return this.prepend(createItem(data));
  264. };
  265. List.prototype.append = function(item) {
  266. return this.insert(item);
  267. };
  268. List.prototype.appendData = function(data) {
  269. return this.insert(createItem(data));
  270. };
  271. List.prototype.insert = function(item, before) {
  272. if (before !== undefined && before !== null) {
  273. // prev before
  274. // ^
  275. // item
  276. this.updateCursors(before.prev, item, before, item);
  277. if (before.prev === null) {
  278. // insert to the beginning of list
  279. if (this.head !== before) {
  280. throw new Error('before doesn\'t belong to list');
  281. }
  282. // since head points to before therefore list doesn't empty
  283. // no need to check tail
  284. this.head = item;
  285. before.prev = item;
  286. item.next = before;
  287. this.updateCursors(null, item);
  288. } else {
  289. // insert between two items
  290. before.prev.next = item;
  291. item.prev = before.prev;
  292. before.prev = item;
  293. item.next = before;
  294. }
  295. } else {
  296. // tail
  297. // ^
  298. // item
  299. this.updateCursors(this.tail, item, null, item);
  300. // insert to the ending of the list
  301. if (this.tail !== null) {
  302. // last item -> new item
  303. this.tail.next = item;
  304. // last item <- new item
  305. item.prev = this.tail;
  306. } else {
  307. // if list has no tail, then it also has no head
  308. // in this case head points to new item
  309. this.head = item;
  310. }
  311. // tail always points to new item
  312. this.tail = item;
  313. }
  314. return this;
  315. };
  316. List.prototype.insertData = function(data, before) {
  317. return this.insert(createItem(data), before);
  318. };
  319. List.prototype.remove = function(item) {
  320. // item
  321. // ^
  322. // prev next
  323. this.updateCursors(item, item.prev, item, item.next);
  324. if (item.prev !== null) {
  325. item.prev.next = item.next;
  326. } else {
  327. if (this.head !== item) {
  328. throw new Error('item doesn\'t belong to list');
  329. }
  330. this.head = item.next;
  331. }
  332. if (item.next !== null) {
  333. item.next.prev = item.prev;
  334. } else {
  335. if (this.tail !== item) {
  336. throw new Error('item doesn\'t belong to list');
  337. }
  338. this.tail = item.prev;
  339. }
  340. item.prev = null;
  341. item.next = null;
  342. return item;
  343. };
  344. List.prototype.push = function(data) {
  345. this.insert(createItem(data));
  346. };
  347. List.prototype.pop = function() {
  348. if (this.tail !== null) {
  349. return this.remove(this.tail);
  350. }
  351. };
  352. List.prototype.unshift = function(data) {
  353. this.prepend(createItem(data));
  354. };
  355. List.prototype.shift = function() {
  356. if (this.head !== null) {
  357. return this.remove(this.head);
  358. }
  359. };
  360. List.prototype.prependList = function(list) {
  361. return this.insertList(list, this.head);
  362. };
  363. List.prototype.appendList = function(list) {
  364. return this.insertList(list);
  365. };
  366. List.prototype.insertList = function(list, before) {
  367. // ignore empty lists
  368. if (list.head === null) {
  369. return this;
  370. }
  371. if (before !== undefined && before !== null) {
  372. this.updateCursors(before.prev, list.tail, before, list.head);
  373. // insert in the middle of dist list
  374. if (before.prev !== null) {
  375. // before.prev <-> list.head
  376. before.prev.next = list.head;
  377. list.head.prev = before.prev;
  378. } else {
  379. this.head = list.head;
  380. }
  381. before.prev = list.tail;
  382. list.tail.next = before;
  383. } else {
  384. this.updateCursors(this.tail, list.tail, null, list.head);
  385. // insert to end of the list
  386. if (this.tail !== null) {
  387. // if destination list has a tail, then it also has a head,
  388. // but head doesn't change
  389. // dest tail -> source head
  390. this.tail.next = list.head;
  391. // dest tail <- source head
  392. list.head.prev = this.tail;
  393. } else {
  394. // if list has no a tail, then it also has no a head
  395. // in this case points head to new item
  396. this.head = list.head;
  397. }
  398. // tail always start point to new item
  399. this.tail = list.tail;
  400. }
  401. list.head = null;
  402. list.tail = null;
  403. return this;
  404. };
  405. List.prototype.replace = function(oldItem, newItemOrList) {
  406. if ('head' in newItemOrList) {
  407. this.insertList(newItemOrList, oldItem);
  408. } else {
  409. this.insert(newItemOrList, oldItem);
  410. }
  411. this.remove(oldItem);
  412. };
  413. var List_1 = List;
  414. var createCustomError = function createCustomError(name, message) {
  415. // use Object.create(), because some VMs prevent setting line/column otherwise
  416. // (iOS Safari 10 even throws an exception)
  417. var error = Object.create(SyntaxError.prototype);
  418. var errorStack = new Error();
  419. error.name = name;
  420. error.message = message;
  421. Object.defineProperty(error, 'stack', {
  422. get: function() {
  423. return (errorStack.stack || '').replace(/^(.+\n){1,3}/, name + ': ' + message + '\n');
  424. }
  425. });
  426. return error;
  427. };
  428. var MAX_LINE_LENGTH = 100;
  429. var OFFSET_CORRECTION = 60;
  430. var TAB_REPLACEMENT = ' ';
  431. function sourceFragment(error, extraLines) {
  432. function processLines(start, end) {
  433. return lines.slice(start, end).map(function(line, idx) {
  434. var num = String(start + idx + 1);
  435. while (num.length < maxNumLength) {
  436. num = ' ' + num;
  437. }
  438. return num + ' |' + line;
  439. }).join('\n');
  440. }
  441. var lines = error.source.split(/\r\n?|\n|\f/);
  442. var line = error.line;
  443. var column = error.column;
  444. var startLine = Math.max(1, line - extraLines) - 1;
  445. var endLine = Math.min(line + extraLines, lines.length + 1);
  446. var maxNumLength = Math.max(4, String(endLine).length) + 1;
  447. var cutLeft = 0;
  448. // column correction according to replaced tab before column
  449. column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length;
  450. if (column > MAX_LINE_LENGTH) {
  451. cutLeft = column - OFFSET_CORRECTION + 3;
  452. column = OFFSET_CORRECTION - 2;
  453. }
  454. for (var i = startLine; i <= endLine; i++) {
  455. if (i >= 0 && i < lines.length) {
  456. lines[i] = lines[i].replace(/\t/g, TAB_REPLACEMENT);
  457. lines[i] =
  458. (cutLeft > 0 && lines[i].length > cutLeft ? '\u2026' : '') +
  459. lines[i].substr(cutLeft, MAX_LINE_LENGTH - 2) +
  460. (lines[i].length > cutLeft + MAX_LINE_LENGTH - 1 ? '\u2026' : '');
  461. }
  462. }
  463. return [
  464. processLines(startLine, line),
  465. new Array(column + maxNumLength + 2).join('-') + '^',
  466. processLines(line, endLine)
  467. ].filter(Boolean).join('\n');
  468. }
  469. var SyntaxError$1 = function(message, source, offset, line, column) {
  470. var error = createCustomError('SyntaxError', message);
  471. error.source = source;
  472. error.offset = offset;
  473. error.line = line;
  474. error.column = column;
  475. error.sourceFragment = function(extraLines) {
  476. return sourceFragment(error, isNaN(extraLines) ? 0 : extraLines);
  477. };
  478. Object.defineProperty(error, 'formattedMessage', {
  479. get: function() {
  480. return (
  481. 'Parse error: ' + error.message + '\n' +
  482. sourceFragment(error, 2)
  483. );
  484. }
  485. });
  486. // for backward capability
  487. error.parseError = {
  488. offset: offset,
  489. line: line,
  490. column: column
  491. };
  492. return error;
  493. };
  494. var _SyntaxError = SyntaxError$1;
  495. // CSS Syntax Module Level 3
  496. // https://www.w3.org/TR/css-syntax-3/
  497. var TYPE = {
  498. EOF: 0, // <EOF-token>
  499. Ident: 1, // <ident-token>
  500. Function: 2, // <function-token>
  501. AtKeyword: 3, // <at-keyword-token>
  502. Hash: 4, // <hash-token>
  503. String: 5, // <string-token>
  504. BadString: 6, // <bad-string-token>
  505. Url: 7, // <url-token>
  506. BadUrl: 8, // <bad-url-token>
  507. Delim: 9, // <delim-token>
  508. Number: 10, // <number-token>
  509. Percentage: 11, // <percentage-token>
  510. Dimension: 12, // <dimension-token>
  511. WhiteSpace: 13, // <whitespace-token>
  512. CDO: 14, // <CDO-token>
  513. CDC: 15, // <CDC-token>
  514. Colon: 16, // <colon-token> :
  515. Semicolon: 17, // <semicolon-token> ;
  516. Comma: 18, // <comma-token> ,
  517. LeftSquareBracket: 19, // <[-token>
  518. RightSquareBracket: 20, // <]-token>
  519. LeftParenthesis: 21, // <(-token>
  520. RightParenthesis: 22, // <)-token>
  521. LeftCurlyBracket: 23, // <{-token>
  522. RightCurlyBracket: 24, // <}-token>
  523. Comment: 25
  524. };
  525. var NAME = Object.keys(TYPE).reduce(function(result, key) {
  526. result[TYPE[key]] = key;
  527. return result;
  528. }, {});
  529. var _const = {
  530. TYPE: TYPE,
  531. NAME: NAME
  532. };
  533. var EOF = 0;
  534. // https://drafts.csswg.org/css-syntax-3/
  535. // § 4.2. Definitions
  536. // digit
  537. // A code point between U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9).
  538. function isDigit(code) {
  539. return code >= 0x0030 && code <= 0x0039;
  540. }
  541. // hex digit
  542. // A digit, or a code point between U+0041 LATIN CAPITAL LETTER A (A) and U+0046 LATIN CAPITAL LETTER F (F),
  543. // or a code point between U+0061 LATIN SMALL LETTER A (a) and U+0066 LATIN SMALL LETTER F (f).
  544. function isHexDigit(code) {
  545. return (
  546. isDigit(code) || // 0 .. 9
  547. (code >= 0x0041 && code <= 0x0046) || // A .. F
  548. (code >= 0x0061 && code <= 0x0066) // a .. f
  549. );
  550. }
  551. // uppercase letter
  552. // A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z).
  553. function isUppercaseLetter(code) {
  554. return code >= 0x0041 && code <= 0x005A;
  555. }
  556. // lowercase letter
  557. // A code point between U+0061 LATIN SMALL LETTER A (a) and U+007A LATIN SMALL LETTER Z (z).
  558. function isLowercaseLetter(code) {
  559. return code >= 0x0061 && code <= 0x007A;
  560. }
  561. // letter
  562. // An uppercase letter or a lowercase letter.
  563. function isLetter(code) {
  564. return isUppercaseLetter(code) || isLowercaseLetter(code);
  565. }
  566. // non-ASCII code point
  567. // A code point with a value equal to or greater than U+0080 <control>.
  568. function isNonAscii(code) {
  569. return code >= 0x0080;
  570. }
  571. // name-start code point
  572. // A letter, a non-ASCII code point, or U+005F LOW LINE (_).
  573. function isNameStart(code) {
  574. return isLetter(code) || isNonAscii(code) || code === 0x005F;
  575. }
  576. // name code point
  577. // A name-start code point, a digit, or U+002D HYPHEN-MINUS (-).
  578. function isName(code) {
  579. return isNameStart(code) || isDigit(code) || code === 0x002D;
  580. }
  581. // non-printable code point
  582. // A code point between U+0000 NULL and U+0008 BACKSPACE, or U+000B LINE TABULATION,
  583. // or a code point between U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE, or U+007F DELETE.
  584. function isNonPrintable(code) {
  585. return (
  586. (code >= 0x0000 && code <= 0x0008) ||
  587. (code === 0x000B) ||
  588. (code >= 0x000E && code <= 0x001F) ||
  589. (code === 0x007F)
  590. );
  591. }
  592. // newline
  593. // U+000A LINE FEED. Note that U+000D CARRIAGE RETURN and U+000C FORM FEED are not included in this definition,
  594. // as they are converted to U+000A LINE FEED during preprocessing.
  595. // TODO: we doesn't do a preprocessing, so check a code point for U+000D CARRIAGE RETURN and U+000C FORM FEED
  596. function isNewline(code) {
  597. return code === 0x000A || code === 0x000D || code === 0x000C;
  598. }
  599. // whitespace
  600. // A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE.
  601. function isWhiteSpace(code) {
  602. return isNewline(code) || code === 0x0020 || code === 0x0009;
  603. }
  604. // § 4.3.8. Check if two code points are a valid escape
  605. function isValidEscape(first, second) {
  606. // If the first code point is not U+005C REVERSE SOLIDUS (\), return false.
  607. if (first !== 0x005C) {
  608. return false;
  609. }
  610. // Otherwise, if the second code point is a newline or EOF, return false.
  611. if (isNewline(second) || second === EOF) {
  612. return false;
  613. }
  614. // Otherwise, return true.
  615. return true;
  616. }
  617. // § 4.3.9. Check if three code points would start an identifier
  618. function isIdentifierStart(first, second, third) {
  619. // Look at the first code point:
  620. // U+002D HYPHEN-MINUS
  621. if (first === 0x002D) {
  622. // If the second code point is a name-start code point or a U+002D HYPHEN-MINUS,
  623. // or the second and third code points are a valid escape, return true. Otherwise, return false.
  624. return (
  625. isNameStart(second) ||
  626. second === 0x002D ||
  627. isValidEscape(second, third)
  628. );
  629. }
  630. // name-start code point
  631. if (isNameStart(first)) {
  632. // Return true.
  633. return true;
  634. }
  635. // U+005C REVERSE SOLIDUS (\)
  636. if (first === 0x005C) {
  637. // If the first and second code points are a valid escape, return true. Otherwise, return false.
  638. return isValidEscape(first, second);
  639. }
  640. // anything else
  641. // Return false.
  642. return false;
  643. }
  644. // § 4.3.10. Check if three code points would start a number
  645. function isNumberStart(first, second, third) {
  646. // Look at the first code point:
  647. // U+002B PLUS SIGN (+)
  648. // U+002D HYPHEN-MINUS (-)
  649. if (first === 0x002B || first === 0x002D) {
  650. // If the second code point is a digit, return true.
  651. if (isDigit(second)) {
  652. return 2;
  653. }
  654. // Otherwise, if the second code point is a U+002E FULL STOP (.)
  655. // and the third code point is a digit, return true.
  656. // Otherwise, return false.
  657. return second === 0x002E && isDigit(third) ? 3 : 0;
  658. }
  659. // U+002E FULL STOP (.)
  660. if (first === 0x002E) {
  661. // If the second code point is a digit, return true. Otherwise, return false.
  662. return isDigit(second) ? 2 : 0;
  663. }
  664. // digit
  665. if (isDigit(first)) {
  666. // Return true.
  667. return 1;
  668. }
  669. // anything else
  670. // Return false.
  671. return 0;
  672. }
  673. //
  674. // Misc
  675. //
  676. // detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark)
  677. function isBOM(code) {
  678. // UTF-16BE
  679. if (code === 0xFEFF) {
  680. return 1;
  681. }
  682. // UTF-16LE
  683. if (code === 0xFFFE) {
  684. return 1;
  685. }
  686. return 0;
  687. }
  688. // Fast code category
  689. //
  690. // https://drafts.csswg.org/css-syntax/#tokenizer-definitions
  691. // > non-ASCII code point
  692. // > A code point with a value equal to or greater than U+0080 <control>
  693. // > name-start code point
  694. // > A letter, a non-ASCII code point, or U+005F LOW LINE (_).
  695. // > name code point
  696. // > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-)
  697. // That means only ASCII code points has a special meaning and we define a maps for 0..127 codes only
  698. var CATEGORY = new Array(0x80);
  699. charCodeCategory.Eof = 0x80;
  700. charCodeCategory.WhiteSpace = 0x82;
  701. charCodeCategory.Digit = 0x83;
  702. charCodeCategory.NameStart = 0x84;
  703. charCodeCategory.NonPrintable = 0x85;
  704. for (var i = 0; i < CATEGORY.length; i++) {
  705. switch (true) {
  706. case isWhiteSpace(i):
  707. CATEGORY[i] = charCodeCategory.WhiteSpace;
  708. break;
  709. case isDigit(i):
  710. CATEGORY[i] = charCodeCategory.Digit;
  711. break;
  712. case isNameStart(i):
  713. CATEGORY[i] = charCodeCategory.NameStart;
  714. break;
  715. case isNonPrintable(i):
  716. CATEGORY[i] = charCodeCategory.NonPrintable;
  717. break;
  718. default:
  719. CATEGORY[i] = i || charCodeCategory.Eof;
  720. }
  721. }
  722. function charCodeCategory(code) {
  723. return code < 0x80 ? CATEGORY[code] : charCodeCategory.NameStart;
  724. }
  725. var charCodeDefinitions = {
  726. isDigit: isDigit,
  727. isHexDigit: isHexDigit,
  728. isUppercaseLetter: isUppercaseLetter,
  729. isLowercaseLetter: isLowercaseLetter,
  730. isLetter: isLetter,
  731. isNonAscii: isNonAscii,
  732. isNameStart: isNameStart,
  733. isName: isName,
  734. isNonPrintable: isNonPrintable,
  735. isNewline: isNewline,
  736. isWhiteSpace: isWhiteSpace,
  737. isValidEscape: isValidEscape,
  738. isIdentifierStart: isIdentifierStart,
  739. isNumberStart: isNumberStart,
  740. isBOM: isBOM,
  741. charCodeCategory: charCodeCategory
  742. };
  743. var isDigit$1 = charCodeDefinitions.isDigit;
  744. var isHexDigit$1 = charCodeDefinitions.isHexDigit;
  745. var isUppercaseLetter$1 = charCodeDefinitions.isUppercaseLetter;
  746. var isName$1 = charCodeDefinitions.isName;
  747. var isWhiteSpace$1 = charCodeDefinitions.isWhiteSpace;
  748. var isValidEscape$1 = charCodeDefinitions.isValidEscape;
  749. function getCharCode(source, offset) {
  750. return offset < source.length ? source.charCodeAt(offset) : 0;
  751. }
  752. function getNewlineLength(source, offset, code) {
  753. if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) {
  754. return 2;
  755. }
  756. return 1;
  757. }
  758. function cmpChar(testStr, offset, referenceCode) {
  759. var code = testStr.charCodeAt(offset);
  760. // code.toLowerCase() for A..Z
  761. if (isUppercaseLetter$1(code)) {
  762. code = code | 32;
  763. }
  764. return code === referenceCode;
  765. }
  766. function cmpStr(testStr, start, end, referenceStr) {
  767. if (end - start !== referenceStr.length) {
  768. return false;
  769. }
  770. if (start < 0 || end > testStr.length) {
  771. return false;
  772. }
  773. for (var i = start; i < end; i++) {
  774. var testCode = testStr.charCodeAt(i);
  775. var referenceCode = referenceStr.charCodeAt(i - start);
  776. // testCode.toLowerCase() for A..Z
  777. if (isUppercaseLetter$1(testCode)) {
  778. testCode = testCode | 32;
  779. }
  780. if (testCode !== referenceCode) {
  781. return false;
  782. }
  783. }
  784. return true;
  785. }
  786. function findWhiteSpaceStart(source, offset) {
  787. for (; offset >= 0; offset--) {
  788. if (!isWhiteSpace$1(source.charCodeAt(offset))) {
  789. break;
  790. }
  791. }
  792. return offset + 1;
  793. }
  794. function findWhiteSpaceEnd(source, offset) {
  795. for (; offset < source.length; offset++) {
  796. if (!isWhiteSpace$1(source.charCodeAt(offset))) {
  797. break;
  798. }
  799. }
  800. return offset;
  801. }
  802. function findDecimalNumberEnd(source, offset) {
  803. for (; offset < source.length; offset++) {
  804. if (!isDigit$1(source.charCodeAt(offset))) {
  805. break;
  806. }
  807. }
  808. return offset;
  809. }
  810. // § 4.3.7. Consume an escaped code point
  811. function consumeEscaped(source, offset) {
  812. // It assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed and
  813. // that the next input code point has already been verified to be part of a valid escape.
  814. offset += 2;
  815. // hex digit
  816. if (isHexDigit$1(getCharCode(source, offset - 1))) {
  817. // Consume as many hex digits as possible, but no more than 5.
  818. // Note that this means 1-6 hex digits have been consumed in total.
  819. for (var maxOffset = Math.min(source.length, offset + 5); offset < maxOffset; offset++) {
  820. if (!isHexDigit$1(getCharCode(source, offset))) {
  821. break;
  822. }
  823. }
  824. // If the next input code point is whitespace, consume it as well.
  825. var code = getCharCode(source, offset);
  826. if (isWhiteSpace$1(code)) {
  827. offset += getNewlineLength(source, offset, code);
  828. }
  829. }
  830. return offset;
  831. }
  832. // §4.3.11. Consume a name
  833. // Note: This algorithm does not do the verification of the first few code points that are necessary
  834. // to ensure the returned code points would constitute an <ident-token>. If that is the intended use,
  835. // ensure that the stream starts with an identifier before calling this algorithm.
  836. function consumeName(source, offset) {
  837. // Let result initially be an empty string.
  838. // Repeatedly consume the next input code point from the stream:
  839. for (; offset < source.length; offset++) {
  840. var code = source.charCodeAt(offset);
  841. // name code point
  842. if (isName$1(code)) {
  843. // Append the code point to result.
  844. continue;
  845. }
  846. // the stream starts with a valid escape
  847. if (isValidEscape$1(code, getCharCode(source, offset + 1))) {
  848. // Consume an escaped code point. Append the returned code point to result.
  849. offset = consumeEscaped(source, offset) - 1;
  850. continue;
  851. }
  852. // anything else
  853. // Reconsume the current input code point. Return result.
  854. break;
  855. }
  856. return offset;
  857. }
  858. // §4.3.12. Consume a number
  859. function consumeNumber(source, offset) {
  860. var code = source.charCodeAt(offset);
  861. // 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-),
  862. // consume it and append it to repr.
  863. if (code === 0x002B || code === 0x002D) {
  864. code = source.charCodeAt(offset += 1);
  865. }
  866. // 3. While the next input code point is a digit, consume it and append it to repr.
  867. if (isDigit$1(code)) {
  868. offset = findDecimalNumberEnd(source, offset + 1);
  869. code = source.charCodeAt(offset);
  870. }
  871. // 4. If the next 2 input code points are U+002E FULL STOP (.) followed by a digit, then:
  872. if (code === 0x002E && isDigit$1(source.charCodeAt(offset + 1))) {
  873. // 4.1 Consume them.
  874. // 4.2 Append them to repr.
  875. code = source.charCodeAt(offset += 2);
  876. // 4.3 Set type to "number".
  877. // TODO
  878. // 4.4 While the next input code point is a digit, consume it and append it to repr.
  879. offset = findDecimalNumberEnd(source, offset);
  880. }
  881. // 5. If the next 2 or 3 input code points are U+0045 LATIN CAPITAL LETTER E (E)
  882. // or U+0065 LATIN SMALL LETTER E (e), ... , followed by a digit, then:
  883. if (cmpChar(source, offset, 101 /* e */)) {
  884. var sign = 0;
  885. code = source.charCodeAt(offset + 1);
  886. // ... optionally followed by U+002D HYPHEN-MINUS (-) or U+002B PLUS SIGN (+) ...
  887. if (code === 0x002D || code === 0x002B) {
  888. sign = 1;
  889. code = source.charCodeAt(offset + 2);
  890. }
  891. // ... followed by a digit
  892. if (isDigit$1(code)) {
  893. // 5.1 Consume them.
  894. // 5.2 Append them to repr.
  895. // 5.3 Set type to "number".
  896. // TODO
  897. // 5.4 While the next input code point is a digit, consume it and append it to repr.
  898. offset = findDecimalNumberEnd(source, offset + 1 + sign + 1);
  899. }
  900. }
  901. return offset;
  902. }
  903. // § 4.3.14. Consume the remnants of a bad url
  904. // ... its sole use is to consume enough of the input stream to reach a recovery point
  905. // where normal tokenizing can resume.
  906. function consumeBadUrlRemnants(source, offset) {
  907. // Repeatedly consume the next input code point from the stream:
  908. for (; offset < source.length; offset++) {
  909. var code = source.charCodeAt(offset);
  910. // U+0029 RIGHT PARENTHESIS ())
  911. // EOF
  912. if (code === 0x0029) {
  913. // Return.
  914. offset++;
  915. break;
  916. }
  917. if (isValidEscape$1(code, getCharCode(source, offset + 1))) {
  918. // Consume an escaped code point.
  919. // Note: This allows an escaped right parenthesis ("\)") to be encountered
  920. // without ending the <bad-url-token>. This is otherwise identical to
  921. // the "anything else" clause.
  922. offset = consumeEscaped(source, offset);
  923. }
  924. }
  925. return offset;
  926. }
  927. var utils = {
  928. consumeEscaped: consumeEscaped,
  929. consumeName: consumeName,
  930. consumeNumber: consumeNumber,
  931. consumeBadUrlRemnants: consumeBadUrlRemnants,
  932. cmpChar: cmpChar,
  933. cmpStr: cmpStr,
  934. getNewlineLength: getNewlineLength,
  935. findWhiteSpaceStart: findWhiteSpaceStart,
  936. findWhiteSpaceEnd: findWhiteSpaceEnd
  937. };
  938. var TYPE$1 = _const.TYPE;
  939. var NAME$1 = _const.NAME;
  940. var cmpStr$1 = utils.cmpStr;
  941. var EOF$1 = TYPE$1.EOF;
  942. var WHITESPACE = TYPE$1.WhiteSpace;
  943. var COMMENT = TYPE$1.Comment;
  944. var OFFSET_MASK = 0x00FFFFFF;
  945. var TYPE_SHIFT = 24;
  946. var TokenStream = function() {
  947. this.offsetAndType = null;
  948. this.balance = null;
  949. this.reset();
  950. };
  951. TokenStream.prototype = {
  952. reset: function() {
  953. this.eof = false;
  954. this.tokenIndex = -1;
  955. this.tokenType = 0;
  956. this.tokenStart = this.firstCharOffset;
  957. this.tokenEnd = this.firstCharOffset;
  958. },
  959. lookupType: function(offset) {
  960. offset += this.tokenIndex;
  961. if (offset < this.tokenCount) {
  962. return this.offsetAndType[offset] >> TYPE_SHIFT;
  963. }
  964. return EOF$1;
  965. },
  966. lookupOffset: function(offset) {
  967. offset += this.tokenIndex;
  968. if (offset < this.tokenCount) {
  969. return this.offsetAndType[offset - 1] & OFFSET_MASK;
  970. }
  971. return this.source.length;
  972. },
  973. lookupValue: function(offset, referenceStr) {
  974. offset += this.tokenIndex;
  975. if (offset < this.tokenCount) {
  976. return cmpStr$1(
  977. this.source,
  978. this.offsetAndType[offset - 1] & OFFSET_MASK,
  979. this.offsetAndType[offset] & OFFSET_MASK,
  980. referenceStr
  981. );
  982. }
  983. return false;
  984. },
  985. getTokenStart: function(tokenIndex) {
  986. if (tokenIndex === this.tokenIndex) {
  987. return this.tokenStart;
  988. }
  989. if (tokenIndex > 0) {
  990. return tokenIndex < this.tokenCount
  991. ? this.offsetAndType[tokenIndex - 1] & OFFSET_MASK
  992. : this.offsetAndType[this.tokenCount] & OFFSET_MASK;
  993. }
  994. return this.firstCharOffset;
  995. },
  996. // TODO: -> skipUntilBalanced
  997. getRawLength: function(startToken, mode) {
  998. var cursor = startToken;
  999. var balanceEnd;
  1000. var offset = this.offsetAndType[Math.max(cursor - 1, 0)] & OFFSET_MASK;
  1001. var type;
  1002. loop:
  1003. for (; cursor < this.tokenCount; cursor++) {
  1004. balanceEnd = this.balance[cursor];
  1005. // stop scanning on balance edge that points to offset before start token
  1006. if (balanceEnd < startToken) {
  1007. break loop;
  1008. }
  1009. type = this.offsetAndType[cursor] >> TYPE_SHIFT;
  1010. // check token is stop type
  1011. switch (mode(type, this.source, offset)) {
  1012. case 1:
  1013. break loop;
  1014. case 2:
  1015. cursor++;
  1016. break loop;
  1017. default:
  1018. offset = this.offsetAndType[cursor] & OFFSET_MASK;
  1019. // fast forward to the end of balanced block
  1020. if (this.balance[balanceEnd] === cursor) {
  1021. cursor = balanceEnd;
  1022. }
  1023. }
  1024. }
  1025. return cursor - this.tokenIndex;
  1026. },
  1027. isBalanceEdge: function(pos) {
  1028. return this.balance[this.tokenIndex] < pos;
  1029. },
  1030. isDelim: function(code, offset) {
  1031. if (offset) {
  1032. return (
  1033. this.lookupType(offset) === TYPE$1.Delim &&
  1034. this.source.charCodeAt(this.lookupOffset(offset)) === code
  1035. );
  1036. }
  1037. return (
  1038. this.tokenType === TYPE$1.Delim &&
  1039. this.source.charCodeAt(this.tokenStart) === code
  1040. );
  1041. },
  1042. getTokenValue: function() {
  1043. return this.source.substring(this.tokenStart, this.tokenEnd);
  1044. },
  1045. getTokenLength: function() {
  1046. return this.tokenEnd - this.tokenStart;
  1047. },
  1048. substrToCursor: function(start) {
  1049. return this.source.substring(start, this.tokenStart);
  1050. },
  1051. skipWS: function() {
  1052. for (var i = this.tokenIndex, skipTokenCount = 0; i < this.tokenCount; i++, skipTokenCount++) {
  1053. if ((this.offsetAndType[i] >> TYPE_SHIFT) !== WHITESPACE) {
  1054. break;
  1055. }
  1056. }
  1057. if (skipTokenCount > 0) {
  1058. this.skip(skipTokenCount);
  1059. }
  1060. },
  1061. skipSC: function() {
  1062. while (this.tokenType === WHITESPACE || this.tokenType === COMMENT) {
  1063. this.next();
  1064. }
  1065. },
  1066. skip: function(tokenCount) {
  1067. var next = this.tokenIndex + tokenCount;
  1068. if (next < this.tokenCount) {
  1069. this.tokenIndex = next;
  1070. this.tokenStart = this.offsetAndType[next - 1] & OFFSET_MASK;
  1071. next = this.offsetAndType[next];
  1072. this.tokenType = next >> TYPE_SHIFT;
  1073. this.tokenEnd = next & OFFSET_MASK;
  1074. } else {
  1075. this.tokenIndex = this.tokenCount;
  1076. this.next();
  1077. }
  1078. },
  1079. next: function() {
  1080. var next = this.tokenIndex + 1;
  1081. if (next < this.tokenCount) {
  1082. this.tokenIndex = next;
  1083. this.tokenStart = this.tokenEnd;
  1084. next = this.offsetAndType[next];
  1085. this.tokenType = next >> TYPE_SHIFT;
  1086. this.tokenEnd = next & OFFSET_MASK;
  1087. } else {
  1088. this.tokenIndex = this.tokenCount;
  1089. this.eof = true;
  1090. this.tokenType = EOF$1;
  1091. this.tokenStart = this.tokenEnd = this.source.length;
  1092. }
  1093. },
  1094. dump: function() {
  1095. var offset = this.firstCharOffset;
  1096. return Array.prototype.slice.call(this.offsetAndType, 0, this.tokenCount).map(function(item, idx) {
  1097. var start = offset;
  1098. var end = item & OFFSET_MASK;
  1099. offset = end;
  1100. return {
  1101. idx: idx,
  1102. type: NAME$1[item >> TYPE_SHIFT],
  1103. chunk: this.source.substring(start, end),
  1104. balance: this.balance[idx]
  1105. };
  1106. }, this);
  1107. }
  1108. };
  1109. var TokenStream_1 = TokenStream;
  1110. function noop(value) {
  1111. return value;
  1112. }
  1113. function generateMultiplier(multiplier) {
  1114. if (multiplier.min === 0 && multiplier.max === 0) {
  1115. return '*';
  1116. }
  1117. if (multiplier.min === 0 && multiplier.max === 1) {
  1118. return '?';
  1119. }
  1120. if (multiplier.min === 1 && multiplier.max === 0) {
  1121. return multiplier.comma ? '#' : '+';
  1122. }
  1123. if (multiplier.min === 1 && multiplier.max === 1) {
  1124. return '';
  1125. }
  1126. return (
  1127. (multiplier.comma ? '#' : '') +
  1128. (multiplier.min === multiplier.max
  1129. ? '{' + multiplier.min + '}'
  1130. : '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}'
  1131. )
  1132. );
  1133. }
  1134. function generateTypeOpts(node) {
  1135. switch (node.type) {
  1136. case 'Range':
  1137. return (
  1138. ' [' +
  1139. (node.min === null ? '-∞' : node.min) +
  1140. ',' +
  1141. (node.max === null ? '∞' : node.max) +
  1142. ']'
  1143. );
  1144. default:
  1145. throw new Error('Unknown node type `' + node.type + '`');
  1146. }
  1147. }
  1148. function generateSequence(node, decorate, forceBraces, compact) {
  1149. var combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' ';
  1150. var result = node.terms.map(function(term) {
  1151. return generate(term, decorate, forceBraces, compact);
  1152. }).join(combinator);
  1153. if (node.explicit || forceBraces) {
  1154. result = (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]');
  1155. }
  1156. return result;
  1157. }
  1158. function generate(node, decorate, forceBraces, compact) {
  1159. var result;
  1160. switch (node.type) {
  1161. case 'Group':
  1162. result =
  1163. generateSequence(node, decorate, forceBraces, compact) +
  1164. (node.disallowEmpty ? '!' : '');
  1165. break;
  1166. case 'Multiplier':
  1167. // return since node is a composition
  1168. return (
  1169. generate(node.term, decorate, forceBraces, compact) +
  1170. decorate(generateMultiplier(node), node)
  1171. );
  1172. case 'Type':
  1173. result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>';
  1174. break;
  1175. case 'Property':
  1176. result = '<\'' + node.name + '\'>';
  1177. break;
  1178. case 'Keyword':
  1179. result = node.name;
  1180. break;
  1181. case 'AtKeyword':
  1182. result = '@' + node.name;
  1183. break;
  1184. case 'Function':
  1185. result = node.name + '(';
  1186. break;
  1187. case 'String':
  1188. case 'Token':
  1189. result = node.value;
  1190. break;
  1191. case 'Comma':
  1192. result = ',';
  1193. break;
  1194. default:
  1195. throw new Error('Unknown node type `' + node.type + '`');
  1196. }
  1197. return decorate(result, node);
  1198. }
  1199. var generate_1 = function(node, options) {
  1200. var decorate = noop;
  1201. var forceBraces = false;
  1202. var compact = false;
  1203. if (typeof options === 'function') {
  1204. decorate = options;
  1205. } else if (options) {
  1206. forceBraces = Boolean(options.forceBraces);
  1207. compact = Boolean(options.compact);
  1208. if (typeof options.decorate === 'function') {
  1209. decorate = options.decorate;
  1210. }
  1211. }
  1212. return generate(node, decorate, forceBraces, compact);
  1213. };
  1214. function fromMatchResult(matchResult) {
  1215. var tokens = matchResult.tokens;
  1216. var longestMatch = matchResult.longestMatch;
  1217. var node = longestMatch < tokens.length ? tokens[longestMatch].node : null;
  1218. var mismatchOffset = -1;
  1219. var entries = 0;
  1220. var css = '';
  1221. for (var i = 0; i < tokens.length; i++) {
  1222. if (i === longestMatch) {
  1223. mismatchOffset = css.length;
  1224. }
  1225. if (node !== null && tokens[i].node === node) {
  1226. if (i <= longestMatch) {
  1227. entries++;
  1228. } else {
  1229. entries = 0;
  1230. }
  1231. }
  1232. css += tokens[i].value;
  1233. }
  1234. return {
  1235. node: node,
  1236. css: css,
  1237. mismatchOffset: mismatchOffset === -1 ? css.length : mismatchOffset,
  1238. last: node === null || entries > 1
  1239. };
  1240. }
  1241. function getLocation(node, point) {
  1242. var loc = node && node.loc && node.loc[point];
  1243. if (loc) {
  1244. return {
  1245. offset: loc.offset,
  1246. line: loc.line,
  1247. column: loc.column
  1248. };
  1249. }
  1250. return null;
  1251. }
  1252. var SyntaxReferenceError = function(type, referenceName) {
  1253. var error = createCustomError(
  1254. 'SyntaxReferenceError',
  1255. type + (referenceName ? ' `' + referenceName + '`' : '')
  1256. );
  1257. error.reference = referenceName;
  1258. return error;
  1259. };
  1260. var MatchError = function(message, syntax, node, matchResult) {
  1261. var error = createCustomError('SyntaxMatchError', message);
  1262. var details = fromMatchResult(matchResult);
  1263. var mismatchOffset = details.mismatchOffset || 0;
  1264. var badNode = details.node || node;
  1265. var end = getLocation(badNode, 'end');
  1266. var start = details.last ? end : getLocation(badNode, 'start');
  1267. var css = details.css;
  1268. error.rawMessage = message;
  1269. error.syntax = syntax ? generate_1(syntax) : '<generic>';
  1270. error.css = css;
  1271. error.mismatchOffset = mismatchOffset;
  1272. error.loc = {
  1273. source: (badNode && badNode.loc && badNode.loc.source) || '<unknown>',
  1274. start: start,
  1275. end: end
  1276. };
  1277. error.line = start ? start.line : undefined;
  1278. error.column = start ? start.column : undefined;
  1279. error.offset = start ? start.offset : undefined;
  1280. error.message = message + '\n' +
  1281. ' syntax: ' + error.syntax + '\n' +
  1282. ' value: ' + (error.css || '<empty string>') + '\n' +
  1283. ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
  1284. return error;
  1285. };
  1286. var error = {
  1287. SyntaxReferenceError: SyntaxReferenceError,
  1288. MatchError: MatchError
  1289. };
  1290. var hasOwnProperty = Object.prototype.hasOwnProperty;
  1291. var keywords = Object.create(null);
  1292. var properties = Object.create(null);
  1293. var HYPHENMINUS = 45; // '-'.charCodeAt()
  1294. function isCustomProperty(str, offset) {
  1295. offset = offset || 0;
  1296. return str.length - offset >= 2 &&
  1297. str.charCodeAt(offset) === HYPHENMINUS &&
  1298. str.charCodeAt(offset + 1) === HYPHENMINUS;
  1299. }
  1300. function getVendorPrefix(str, offset) {
  1301. offset = offset || 0;
  1302. // verdor prefix should be at least 3 chars length
  1303. if (str.length - offset >= 3) {
  1304. // vendor prefix starts with hyper minus following non-hyper minus
  1305. if (str.charCodeAt(offset) === HYPHENMINUS &&
  1306. str.charCodeAt(offset + 1) !== HYPHENMINUS) {
  1307. // vendor prefix should contain a hyper minus at the ending
  1308. var secondDashIndex = str.indexOf('-', offset + 2);
  1309. if (secondDashIndex !== -1) {
  1310. return str.substring(offset, secondDashIndex + 1);
  1311. }
  1312. }
  1313. }
  1314. return '';
  1315. }
  1316. function getKeywordDescriptor(keyword) {
  1317. if (hasOwnProperty.call(keywords, keyword)) {
  1318. return keywords[keyword];
  1319. }
  1320. var name = keyword.toLowerCase();
  1321. if (hasOwnProperty.call(keywords, name)) {
  1322. return keywords[keyword] = keywords[name];
  1323. }
  1324. var custom = isCustomProperty(name, 0);
  1325. var vendor = !custom ? getVendorPrefix(name, 0) : '';
  1326. return keywords[keyword] = Object.freeze({
  1327. basename: name.substr(vendor.length),
  1328. name: name,
  1329. vendor: vendor,
  1330. prefix: vendor,
  1331. custom: custom
  1332. });
  1333. }
  1334. function getPropertyDescriptor(property) {
  1335. if (hasOwnProperty.call(p