web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3322 lines
258 KiB

  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.csso = {}));
  5. }(this, (function (exports) { 'use strict';
  6. var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  7. function createCommonjsModule(fn, module) {
  8. return module = { exports: {} }, fn(module, module.exports), module.exports;
  9. }
  10. function getCjsExportFromNamespace (n) {
  11. return n && n['default'] || n;
  12. }
  13. var csstree_min = createCommonjsModule(function (module, exports) {
  14. !function(e,t){module.exports=t();}(commonjsGlobal,(function(){function e(e){return {prev:null,next:null,data:e}}function t(e,t,n){var i;return null!==r?(i=r,r=r.cursor,i.prev=t,i.next=n,i.cursor=e.cursor):i={prev:t,next:n,cursor:e.cursor},e.cursor=i,i}function n(e){var t=e.cursor;e.cursor=t.cursor,t.prev=null,t.next=null,t.cursor=r,r=t;}var r=null,i=function(){this.cursor=null,this.head=null,this.tail=null;};i.createItem=e,i.prototype.createItem=e,i.prototype.updateCursors=function(e,t,n,r){for(var i=this.cursor;null!==i;)i.prev===e&&(i.prev=t),i.next===n&&(i.next=r),i=i.cursor;},i.prototype.getSize=function(){for(var e=0,t=this.head;t;)e++,t=t.next;return e},i.prototype.fromArray=function(t){var n=null;this.head=null;for(var r=0;r<t.length;r++){var i=e(t[r]);null!==n?n.next=i:this.head=i,i.prev=n,n=i;}return this.tail=n,this},i.prototype.toArray=function(){for(var e=this.head,t=[];e;)t.push(e.data),e=e.next;return t},i.prototype.toJSON=i.prototype.toArray,i.prototype.isEmpty=function(){return null===this.head},i.prototype.first=function(){return this.head&&this.head.data},i.prototype.last=function(){return this.tail&&this.tail.data},i.prototype.each=function(e,r){var i;void 0===r&&(r=this);for(var a=t(this,null,this.head);null!==a.next;)i=a.next,a.next=i.next,e.call(r,i.data,i,this);n(this);},i.prototype.forEach=i.prototype.each,i.prototype.eachRight=function(e,r){var i;void 0===r&&(r=this);for(var a=t(this,this.tail,null);null!==a.prev;)i=a.prev,a.prev=i.prev,e.call(r,i.data,i,this);n(this);},i.prototype.forEachRight=i.prototype.eachRight,i.prototype.reduce=function(e,r,i){var a;void 0===i&&(i=this);for(var o=t(this,null,this.head),s=r;null!==o.next;)a=o.next,o.next=a.next,s=e.call(i,s,a.data,a,this);return n(this),s},i.prototype.reduceRight=function(e,r,i){var a;void 0===i&&(i=this);for(var o=t(this,this.tail,null),s=r;null!==o.prev;)a=o.prev,o.prev=a.prev,s=e.call(i,s,a.data,a,this);return n(this),s},i.prototype.nextUntil=function(e,r,i){if(null!==e){var a;void 0===i&&(i=this);for(var o=t(this,null,e);null!==o.next&&(a=o.next,o.next=a.next,!r.call(i,a.data,a,this)););n(this);}},i.prototype.prevUntil=function(e,r,i){if(null!==e){var a;void 0===i&&(i=this);for(var o=t(this,e,null);null!==o.prev&&(a=o.prev,o.prev=a.prev,!r.call(i,a.data,a,this)););n(this);}},i.prototype.some=function(e,t){var n=this.head;for(void 0===t&&(t=this);null!==n;){if(e.call(t,n.data,n,this))return !0;n=n.next;}return !1},i.prototype.map=function(e,t){var n=new i,r=this.head;for(void 0===t&&(t=this);null!==r;)n.appendData(e.call(t,r.data,r,this)),r=r.next;return n},i.prototype.filter=function(e,t){var n=new i,r=this.head;for(void 0===t&&(t=this);null!==r;)e.call(t,r.data,r,this)&&n.appendData(r.data),r=r.next;return n},i.prototype.clear=function(){this.head=null,this.tail=null;},i.prototype.copy=function(){for(var t=new i,n=this.head;null!==n;)t.insert(e(n.data)),n=n.next;return t},i.prototype.prepend=function(e){return this.updateCursors(null,e,this.head,e),null!==this.head?(this.head.prev=e,e.next=this.head):this.tail=e,this.head=e,this},i.prototype.prependData=function(t){return this.prepend(e(t))},i.prototype.append=function(e){return this.insert(e)},i.prototype.appendData=function(t){return this.insert(e(t))},i.prototype.insert=function(e,t){if(null!=t)if(this.updateCursors(t.prev,e,t,e),null===t.prev){if(this.head!==t)throw new Error("before doesn't belong to list");this.head=e,t.prev=e,e.next=t,this.updateCursors(null,e);}else t.prev.next=e,e.prev=t.prev,t.prev=e,e.next=t;else this.updateCursors(this.tail,e,null,e),null!==this.tail?(this.tail.next=e,e.prev=this.tail):this.head=e,this.tail=e;return this},i.prototype.insertData=function(t,n){return this.insert(e(t),n)},i.prototype.remove=function(e){if(this.updateCursors(e,e.prev,e,e.next),null!==e.prev)e.prev.next=e.next;else {if(this.head!==e)throw new Error("item doesn't belong to list");this.head=e.next;}if(null!==e.next)e.next.prev=e.prev;else {if(this.tail!==e)throw new Error("item doesn't belong to list");this.tail=e.prev;}return e.prev=null,e.next=null,e},i.prototype.push=functio
  15. });
  16. var hasOwnProperty = Object.prototype.hasOwnProperty;
  17. function buildMap(list, caseInsensitive) {
  18. var map = Object.create(null);
  19. if (!Array.isArray(list)) {
  20. return null;
  21. }
  22. for (var i = 0; i < list.length; i++) {
  23. var name = list[i];
  24. if (caseInsensitive) {
  25. name = name.toLowerCase();
  26. }
  27. map[name] = true;
  28. }
  29. return map;
  30. }
  31. function buildList(data) {
  32. if (!data) {
  33. return null;
  34. }
  35. var tags = buildMap(data.tags, true);
  36. var ids = buildMap(data.ids);
  37. var classes = buildMap(data.classes);
  38. if (tags === null &&
  39. ids === null &&
  40. classes === null) {
  41. return null;
  42. }
  43. return {
  44. tags: tags,
  45. ids: ids,
  46. classes: classes
  47. };
  48. }
  49. function buildIndex(data) {
  50. var scopes = false;
  51. if (data.scopes && Array.isArray(data.scopes)) {
  52. scopes = Object.create(null);
  53. for (var i = 0; i < data.scopes.length; i++) {
  54. var list = data.scopes[i];
  55. if (!list || !Array.isArray(list)) {
  56. throw new Error('Wrong usage format');
  57. }
  58. for (var j = 0; j < list.length; j++) {
  59. var name = list[j];
  60. if (hasOwnProperty.call(scopes, name)) {
  61. throw new Error('Class can\'t be used for several scopes: ' + name);
  62. }
  63. scopes[name] = i + 1;
  64. }
  65. }
  66. }
  67. return {
  68. whitelist: buildList(data),
  69. blacklist: buildList(data.blacklist),
  70. scopes: scopes
  71. };
  72. }
  73. var usage = {
  74. buildIndex: buildIndex
  75. };
  76. var utils = {
  77. hasNoChildren: function(node) {
  78. return !node || !node.children || node.children.isEmpty();
  79. },
  80. isNodeChildrenList: function(node, list) {
  81. return node !== null && node.children === list;
  82. }
  83. };
  84. var resolveKeyword = csstree_min.keyword;
  85. var { hasNoChildren } = utils;
  86. var Atrule = function cleanAtrule(node, item, list) {
  87. if (node.block) {
  88. // otherwise removed at-rule don't prevent @import for removal
  89. if (this.stylesheet !== null) {
  90. this.stylesheet.firstAtrulesAllowed = false;
  91. }
  92. if (hasNoChildren(node.block)) {
  93. list.remove(item);
  94. return;
  95. }
  96. }
  97. switch (node.name) {
  98. case 'charset':
  99. if (hasNoChildren(node.prelude)) {
  100. list.remove(item);
  101. return;
  102. }
  103. // if there is any rule before @charset -> remove it
  104. if (item.prev) {
  105. list.remove(item);
  106. return;
  107. }
  108. break;
  109. case 'import':
  110. if (this.stylesheet === null || !this.stylesheet.firstAtrulesAllowed) {
  111. list.remove(item);
  112. return;
  113. }
  114. // if there are some rules that not an @import or @charset before @import
  115. // remove it
  116. list.prevUntil(item.prev, function(rule) {
  117. if (rule.type === 'Atrule') {
  118. if (rule.name === 'import' || rule.name === 'charset') {
  119. return;
  120. }
  121. }
  122. this.root.firstAtrulesAllowed = false;
  123. list.remove(item);
  124. return true;
  125. }, this);
  126. break;
  127. default:
  128. var name = resolveKeyword(node.name).basename;
  129. if (name === 'keyframes' ||
  130. name === 'media' ||
  131. name === 'supports') {
  132. // drop at-rule with no prelude
  133. if (hasNoChildren(node.prelude) || hasNoChildren(node.block)) {
  134. list.remove(item);
  135. }
  136. }
  137. }
  138. };
  139. var Comment = function cleanComment(data, item, list) {
  140. list.remove(item);
  141. };
  142. var property = csstree_min.property;
  143. var Declaration = function cleanDeclartion(node, item, list) {
  144. if (node.value.children && node.value.children.isEmpty()) {
  145. list.remove(item);
  146. return;
  147. }
  148. if (property(node.property).custom) {
  149. if (/\S/.test(node.value.value)) {
  150. node.value.value = node.value.value.trim();
  151. }
  152. }
  153. };
  154. var { isNodeChildrenList } = utils;
  155. var Raw = function cleanRaw(node, item, list) {
  156. // raw in stylesheet or block children
  157. if (isNodeChildrenList(this.stylesheet, list) ||
  158. isNodeChildrenList(this.block, list)) {
  159. list.remove(item);
  160. }
  161. };
  162. var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
  163. var walk = csstree_min.walk;
  164. var { hasNoChildren: hasNoChildren$1 } = utils;
  165. function cleanUnused(selectorList, usageData) {
  166. selectorList.children.each(function(selector, item, list) {
  167. var shouldRemove = false;
  168. walk(selector, function(node) {
  169. // ignore nodes in nested selectors
  170. if (this.selector === null || this.selector === selectorList) {
  171. switch (node.type) {
  172. case 'SelectorList':
  173. // TODO: remove toLowerCase when pseudo selectors will be normalized
  174. // ignore selectors inside :not()
  175. if (this.function === null || this.function.name.toLowerCase() !== 'not') {
  176. if (cleanUnused(node, usageData)) {
  177. shouldRemove = true;
  178. }
  179. }
  180. break;
  181. case 'ClassSelector':
  182. if (usageData.whitelist !== null &&
  183. usageData.whitelist.classes !== null &&
  184. !hasOwnProperty$1.call(usageData.whitelist.classes, node.name)) {
  185. shouldRemove = true;
  186. }
  187. if (usageData.blacklist !== null &&
  188. usageData.blacklist.classes !== null &&
  189. hasOwnProperty$1.call(usageData.blacklist.classes, node.name)) {
  190. shouldRemove = true;
  191. }
  192. break;
  193. case 'IdSelector':
  194. if (usageData.whitelist !== null &&
  195. usageData.whitelist.ids !== null &&
  196. !hasOwnProperty$1.call(usageData.whitelist.ids, node.name)) {
  197. shouldRemove = true;
  198. }
  199. if (usageData.blacklist !== null &&
  200. usageData.blacklist.ids !== null &&
  201. hasOwnProperty$1.call(usageData.blacklist.ids, node.name)) {
  202. shouldRemove = true;
  203. }
  204. break;
  205. case 'TypeSelector':
  206. // TODO: remove toLowerCase when type selectors will be normalized
  207. // ignore universal selectors
  208. if (node.name.charAt(node.name.length - 1) !== '*') {
  209. if (usageData.whitelist !== null &&
  210. usageData.whitelist.tags !== null &&
  211. !hasOwnProperty$1.call(usageData.whitelist.tags, node.name.toLowerCase())) {
  212. shouldRemove = true;
  213. }
  214. if (usageData.blacklist !== null &&
  215. usageData.blacklist.tags !== null &&
  216. hasOwnProperty$1.call(usageData.blacklist.tags, node.name.toLowerCase())) {
  217. shouldRemove = true;
  218. }
  219. }
  220. break;
  221. }
  222. }
  223. });
  224. if (shouldRemove) {
  225. list.remove(item);
  226. }
  227. });
  228. return selectorList.children.isEmpty();
  229. }
  230. var Rule = function cleanRule(node, item, list, options) {
  231. if (hasNoChildren$1(node.prelude) || hasNoChildren$1(node.block)) {
  232. list.remove(item);
  233. return;
  234. }
  235. var usageData = options.usage;
  236. if (usageData && (usageData.whitelist !== null || usageData.blacklist !== null)) {
  237. cleanUnused(node.prelude, usageData);
  238. if (hasNoChildren$1(node.prelude)) {
  239. list.remove(item);
  240. return;
  241. }
  242. }
  243. };
  244. // remove useless universal selector
  245. var TypeSelector = function cleanTypeSelector(node, item, list) {
  246. var name = item.data.name;
  247. // check it's a non-namespaced universal selector
  248. if (name !== '*') {
  249. return;
  250. }
  251. // remove when universal selector before other selectors
  252. var nextType = item.next && item.next.data.type;
  253. if (nextType === 'IdSelector' ||
  254. nextType === 'ClassSelector' ||
  255. nextType === 'AttributeSelector' ||
  256. nextType === 'PseudoClassSelector' ||
  257. nextType === 'PseudoElementSelector') {
  258. list.remove(item);
  259. }
  260. };
  261. var { isNodeChildrenList: isNodeChildrenList$1 } = utils;
  262. function isSafeOperator(node) {
  263. return node.type === 'Operator' && node.value !== '+' && node.value !== '-';
  264. }
  265. var WhiteSpace = function cleanWhitespace(node, item, list) {
  266. // remove when first or last item in sequence
  267. if (item.next === null || item.prev === null) {
  268. list.remove(item);
  269. return;
  270. }
  271. // white space in stylesheet or block children
  272. if (isNodeChildrenList$1(this.stylesheet, list) ||
  273. isNodeChildrenList$1(this.block, list)) {
  274. list.remove(item);
  275. return;
  276. }
  277. if (item.next.data.type === 'WhiteSpace') {
  278. list.remove(item);
  279. return;
  280. }
  281. if (isSafeOperator(item.prev.data) || isSafeOperator(item.next.data)) {
  282. list.remove(item);
  283. return;
  284. }
  285. };
  286. var walk$1 = csstree_min.walk;
  287. var handlers = {
  288. Atrule: Atrule,
  289. Comment: Comment,
  290. Declaration: Declaration,
  291. Raw: Raw,
  292. Rule: Rule,
  293. TypeSelector: TypeSelector,
  294. WhiteSpace: WhiteSpace
  295. };
  296. var clean = function(ast, options) {
  297. walk$1(ast, {
  298. leave: function(node, item, list) {
  299. if (handlers.hasOwnProperty(node.type)) {
  300. handlers[node.type].call(this, node, item, list, options);
  301. }
  302. }
  303. });
  304. };
  305. var keyframes = function(node) {
  306. node.block.children.each(function(rule) {
  307. rule.prelude.children.each(function(simpleselector) {
  308. simpleselector.children.each(function(data, item) {
  309. if (data.type === 'Percentage' && data.value === '100') {
  310. item.data = {
  311. type: 'TypeSelector',
  312. loc: data.loc,
  313. name: 'to'
  314. };
  315. } else if (data.type === 'TypeSelector' && data.name === 'from') {
  316. item.data = {
  317. type: 'Percentage',
  318. loc: data.loc,
  319. value: '0'
  320. };
  321. }
  322. });
  323. });
  324. });
  325. };
  326. var resolveKeyword$1 = csstree_min.keyword;
  327. var Atrule$1 = function(node) {
  328. // compress @keyframe selectors
  329. if (resolveKeyword$1(node.name).basename === 'keyframes') {
  330. keyframes(node);
  331. }
  332. };
  333. // Can unquote attribute detection
  334. // Adopted implementation of Mathias Bynens
  335. // https://github.com/mathiasbynens/mothereff.in/blob/master/unquoted-attributes/eff.js
  336. var escapesRx = /\\([0-9A-Fa-f]{1,6})(\r\n|[ \t\n\f\r])?|\\./g;
  337. var blockUnquoteRx = /^(-?\d|--)|[\u0000-\u002c\u002e\u002f\u003A-\u0040\u005B-\u005E\u0060\u007B-\u009f]/;
  338. function canUnquote(value) {
  339. if (value === '' || value === '-') {
  340. return;
  341. }
  342. // Escapes are valid, so replace them with a valid non-empty string
  343. value = value.replace(escapesRx, 'a');
  344. return !blockUnquoteRx.test(value);
  345. }
  346. var AttributeSelector = function(node) {
  347. var attrValue = node.value;
  348. if (!attrValue || attrValue.type !== 'String') {
  349. return;
  350. }
  351. var unquotedValue = attrValue.value.replace(/^(.)(.*)\1$/, '$2');
  352. if (canUnquote(unquotedValue)) {
  353. node.value = {
  354. type: 'Identifier',
  355. loc: attrValue.loc,
  356. name: unquotedValue
  357. };
  358. }
  359. };
  360. var font = function compressFont(node) {
  361. var list = node.children;
  362. list.eachRight(function(node, item) {
  363. if (node.type === 'Identifier') {
  364. if (node.name === 'bold') {
  365. item.data = {
  366. type: 'Number',
  367. loc: node.loc,
  368. value: '700'
  369. };
  370. } else if (node.name === 'normal') {
  371. var prev = item.prev;
  372. if (prev && prev.data.type === 'Operator' && prev.data.value === '/') {
  373. this.remove(prev);
  374. }
  375. this.remove(item);
  376. } else if (node.name === 'medium') {
  377. var next = item.next;
  378. if (!next || next.data.type !== 'Operator') {
  379. this.remove(item);
  380. }
  381. }
  382. }
  383. });
  384. // remove redundant spaces
  385. list.each(function(node, item) {
  386. if (node.type === 'WhiteSpace') {
  387. if (!item.prev || !item.next || item.next.data.type === 'WhiteSpace') {
  388. this.remove(item);
  389. }
  390. }
  391. });
  392. if (list.isEmpty()) {
  393. list.insert(list.createItem({
  394. type: 'Identifier',
  395. name: 'normal'
  396. }));
  397. }
  398. };
  399. var fontWeight = function compressFontWeight(node) {
  400. var value = node.children.head.data;
  401. if (value.type === 'Identifier') {
  402. switch (value.name) {
  403. case 'normal':
  404. node.children.head.data = {
  405. type: 'Number',
  406. loc: value.loc,
  407. value: '400'
  408. };
  409. break;
  410. case 'bold':
  411. node.children.head.data = {
  412. type: 'Number',
  413. loc: value.loc,
  414. value: '700'
  415. };
  416. break;
  417. }
  418. }
  419. };
  420. var List = csstree_min.List;
  421. var background = function compressBackground(node) {
  422. function lastType() {
  423. if (buffer.length) {
  424. return buffer[buffer.length - 1].type;
  425. }
  426. }
  427. function flush() {
  428. if (lastType() === 'WhiteSpace') {
  429. buffer.pop();
  430. }
  431. if (!buffer.length) {
  432. buffer.unshift(
  433. {
  434. type: 'Number',
  435. loc: null,
  436. value: '0'
  437. },
  438. {
  439. type: 'WhiteSpace',
  440. value: ' '
  441. },
  442. {
  443. type: 'Number',
  444. loc: null,
  445. value: '0'
  446. }
  447. );
  448. }
  449. newValue.push.apply(newValue, buffer);
  450. buffer = [];
  451. }
  452. var newValue = [];
  453. var buffer = [];
  454. node.children.each(function(node) {
  455. if (node.type === 'Operator' && node.value === ',') {
  456. flush();
  457. newValue.push(node);
  458. return;
  459. }
  460. // remove defaults
  461. if (node.type === 'Identifier') {
  462. if (node.name === 'transparent' ||
  463. node.name === 'none' ||
  464. node.name === 'repeat' ||
  465. node.name === 'scroll') {
  466. return;
  467. }
  468. }
  469. // don't add redundant spaces
  470. if (node.type === 'WhiteSpace' && (!buffer.length || lastType() === 'WhiteSpace')) {
  471. return;
  472. }
  473. buffer.push(node);
  474. });
  475. flush();
  476. node.children = new List().fromArray(newValue);
  477. };
  478. function removeItemAndRedundantWhiteSpace(list, item) {
  479. var prev = item.prev;
  480. var next = item.next;
  481. if (next !== null) {
  482. if (next.data.type === 'WhiteSpace' && (prev === null || prev.data.type === 'WhiteSpace')) {
  483. list.remove(next);
  484. }
  485. } else if (prev !== null && prev.data.type === 'WhiteSpace') {
  486. list.remove(prev);
  487. }
  488. list.remove(item);
  489. }
  490. var border = function compressBorder(node) {
  491. node.children.each(function(node, item, list) {
  492. if (node.type === 'Identifier' && node.name.toLowerCase() === 'none') {
  493. if (list.head === list.tail) {
  494. // replace `none` for zero when `none` is a single term
  495. item.data = {
  496. type: 'Number',
  497. loc: node.loc,
  498. value: '0'
  499. };
  500. } else {
  501. removeItemAndRedundantWhiteSpace(list, item);
  502. }
  503. }
  504. });
  505. };
  506. var resolveName = csstree_min.property;
  507. var handlers$1 = {
  508. 'font': font,
  509. 'font-weight': fontWeight,
  510. 'background': background,
  511. 'border': border,
  512. 'outline': border
  513. };
  514. var Value = function compressValue(node) {
  515. if (!this.declaration) {
  516. return;
  517. }
  518. var property = resolveName(this.declaration.property);
  519. if (handlers$1.hasOwnProperty(property.basename)) {
  520. handlers$1[property.basename](node);
  521. }
  522. };
  523. var OMIT_PLUSSIGN = /^(?:\+|(-))?0*(\d*)(?:\.0*|(\.\d*?)0*)?$/;
  524. var KEEP_PLUSSIGN = /^([\+\-])?0*(\d*)(?:\.0*|(\.\d*?)0*)?$/;
  525. var unsafeToRemovePlusSignAfter = {
  526. Dimension: true,
  527. Hash: true,
  528. Identifier: true,
  529. Number: true,
  530. Raw: true,
  531. UnicodeRange: true
  532. };
  533. function packNumber(value, item) {
  534. // omit plus sign only if no prev or prev is safe type
  535. var regexp = item && item.prev !== null && unsafeToRemovePlusSignAfter.hasOwnProperty(item.prev.data.type)
  536. ? KEEP_PLUSSIGN
  537. : OMIT_PLUSSIGN;
  538. // 100 -> '100'
  539. // 00100 -> '100'
  540. // +100 -> '100' (only when safe, e.g. omitting plus sign for 1px+1px leads to single dimension instead of two)
  541. // -100 -> '-100'
  542. // 0.123 -> '.123'
  543. // 0.12300 -> '.123'
  544. // 0.0 -> ''
  545. // 0 -> ''
  546. // -0 -> '-'
  547. value = String(value).replace(regexp, '$1$2$3');
  548. if (value === '' || value === '-') {
  549. value = '0';
  550. }
  551. return value;
  552. }
  553. var _Number = function(node, item) {
  554. node.value = packNumber(node.value, item);
  555. };
  556. var pack = packNumber;
  557. _Number.pack = pack;
  558. var packNumber$1 = _Number.pack;
  559. var MATH_FUNCTIONS = {
  560. 'calc': true,
  561. 'min': true,
  562. 'max': true,
  563. 'clamp': true
  564. };
  565. var LENGTH_UNIT = {
  566. // absolute length units
  567. 'px': true,
  568. 'mm': true,
  569. 'cm': true,
  570. 'in': true,
  571. 'pt': true,
  572. 'pc': true,
  573. // relative length units
  574. 'em': true,
  575. 'ex': true,
  576. 'ch': true,
  577. 'rem': true,
  578. // viewport-percentage lengths
  579. 'vh': true,
  580. 'vw': true,
  581. 'vmin': true,
  582. 'vmax': true,
  583. 'vm': true
  584. };
  585. var Dimension = function compressDimension(node, item) {
  586. var value = packNumber$1(node.value, item);
  587. node.value = value;
  588. if (value === '0' && this.declaration !== null && this.atrulePrelude === null) {
  589. var unit = node.unit.toLowerCase();
  590. // only length values can be compressed
  591. if (!LENGTH_UNIT.hasOwnProperty(unit)) {
  592. return;
  593. }
  594. // issue #362: shouldn't remove unit in -ms-flex since it breaks flex in IE10/11
  595. // issue #200: shouldn't remove unit in flex since it breaks flex in IE10/11
  596. if (this.declaration.property === '-ms-flex' ||
  597. this.declaration.property === 'flex') {
  598. return;
  599. }
  600. // issue #222: don't remove units inside calc
  601. if (this.function && MATH_FUNCTIONS.hasOwnProperty(this.function.name)) {
  602. return;
  603. }
  604. item.data = {
  605. type: 'Number',
  606. loc: node.loc,
  607. value: value
  608. };
  609. }
  610. };
  611. var lexer = csstree_min.lexer;
  612. var packNumber$2 = _Number.pack;
  613. var blacklist = new Set([
  614. // see https://github.com/jakubpawlowicz/clean-css/issues/957
  615. 'width',
  616. 'min-width',
  617. 'max-width',
  618. 'height',
  619. 'min-height',
  620. 'max-height',
  621. // issue #410: Don’t remove units in flex-basis value for (-ms-)flex shorthand
  622. // issue #362: shouldn't remove unit in -ms-flex since it breaks flex in IE10/11
  623. // issue #200: shouldn't remove unit in flex since it breaks flex in IE10/11
  624. 'flex',
  625. '-ms-flex'
  626. ]);
  627. var Percentage = function compressPercentage(node, item) {
  628. node.value = packNumber$2(node.value, item);
  629. if (node.value === '0' && this.declaration && !blacklist.has(this.declaration.property)) {
  630. // try to convert a number
  631. item.data = {
  632. type: 'Number',
  633. loc: node.loc,
  634. value: node.value
  635. };
  636. // that's ok only when new value matches on length
  637. if (!lexer.matchDeclaration(this.declaration).isType(item.data, 'length')) {
  638. // otherwise rollback changes
  639. item.data = node;
  640. }
  641. }
  642. };
  643. var _String = function(node) {
  644. var value = node.value;
  645. // remove escaped newlines, i.e.
  646. // .a { content: "foo\
  647. // bar"}
  648. // ->
  649. // .a { content: "foobar" }
  650. value = value.replace(/\\(\r\n|\r|\n|\f)/g, '');
  651. node.value = value;
  652. };
  653. var UNICODE = '\\\\[0-9a-f]{1,6}(\\r\\n|[ \\n\\r\\t\\f])?';
  654. var ESCAPE = '(' + UNICODE + '|\\\\[^\\n\\r\\f0-9a-fA-F])';
  655. var NONPRINTABLE = '\u0000\u0008\u000b\u000e-\u001f\u007f';
  656. var SAFE_URL = new RegExp('^(' + ESCAPE + '|[^\"\'\\(\\)\\\\\\s' + NONPRINTABLE + '])*$', 'i');
  657. var Url = function(node) {
  658. var value = node.value;
  659. if (value.type !== 'String') {
  660. return;
  661. }
  662. var quote = value.value[0];
  663. var url = value.value.substr(1, value.value.length - 2);
  664. // convert `\\` to `/`
  665. url = url.replace(/\\\\/g, '/');
  666. // remove quotes when safe
  667. // https://www.w3.org/TR/css-syntax-3/#url-unquoted-diagram
  668. if (SAFE_URL.test(url)) {
  669. node.value = {
  670. type: 'Raw',
  671. loc: node.value.loc,
  672. value: url
  673. };
  674. } else {
  675. // use double quotes if string has no double quotes
  676. // otherwise use original quotes
  677. // TODO: make better quote type selection
  678. node.value.value = url.indexOf('"') === -1 ? '"' + url + '"' : quote + url + quote;
  679. }
  680. };
  681. var lexer$1 = csstree_min.lexer;
  682. var packNumber$3 = _Number.pack;
  683. // http://www.w3.org/TR/css3-color/#svg-color
  684. var NAME_TO_HEX = {
  685. 'aliceblue': 'f0f8ff',
  686. 'antiquewhite': 'faebd7',
  687. 'aqua': '0ff',
  688. 'aquamarine': '7fffd4',
  689. 'azure': 'f0ffff',
  690. 'beige': 'f5f5dc',
  691. 'bisque': 'ffe4c4',
  692. 'black': '000',
  693. 'blanchedalmond': 'ffebcd',
  694. 'blue': '00f',
  695. 'blueviolet': '8a2be2',
  696. 'brown': 'a52a2a',
  697. 'burlywood': 'deb887',
  698. 'cadetblue': '5f9ea0',
  699. 'chartreuse': '7fff00',
  700. 'chocolate': 'd2691e',
  701. 'coral': 'ff7f50',
  702. 'cornflowerblue': '6495ed',
  703. 'cornsilk': 'fff8dc',
  704. 'crimson': 'dc143c',
  705. 'cyan': '0ff',
  706. 'darkblue': '00008b',
  707. 'darkcyan': '008b8b',
  708. 'darkgoldenrod': 'b8860b',
  709. 'darkgray': 'a9a9a9',
  710. 'darkgrey': 'a9a9a9',
  711. 'darkgreen': '006400',
  712. 'darkkhaki': 'bdb76b',
  713. 'darkmagenta': '8b008b',
  714. 'darkolivegreen': '556b2f',
  715. 'darkorange': 'ff8c00',
  716. 'darkorchid': '9932cc',
  717. 'darkred': '8b0000',
  718. 'darksalmon': 'e9967a',
  719. 'darkseagreen': '8fbc8f',
  720. 'darkslateblue': '483d8b',
  721. 'darkslategray': '2f4f4f',
  722. 'darkslategrey': '2f4f4f',
  723. 'darkturquoise': '00ced1',
  724. 'darkviolet': '9400d3',
  725. 'deeppink': 'ff1493',
  726. 'deepskyblue': '00bfff',
  727. 'dimgray': '696969',
  728. 'dimgrey': '696969',
  729. 'dodgerblue': '1e90ff',
  730. 'firebrick': 'b22222',
  731. 'floralwhite': 'fffaf0',
  732. 'forestgreen': '228b22',
  733. 'fuchsia': 'f0f',
  734. 'gainsboro': 'dcdcdc',
  735. 'ghostwhite': 'f8f8ff',
  736. 'gold': 'ffd700',
  737. 'goldenrod': 'daa520',
  738. 'gray': '808080',
  739. 'grey': '808080',
  740. 'green': '008000',
  741. 'greenyellow': 'adff2f',
  742. 'honeydew': 'f0fff0',
  743. 'hotpink': 'ff69b4',
  744. 'indianred': 'cd5c5c',
  745. 'indigo': '4b0082',
  746. 'ivory': 'fffff0',
  747. 'khaki': 'f0e68c',
  748. 'lavender': 'e6e6fa',
  749. 'lavenderblush': 'fff0f5',
  750. 'lawngreen': '7cfc00',
  751. 'lemonchiffon': 'fffacd',
  752. 'lightblue': 'add8e6',
  753. 'lightcoral': 'f08080',
  754. 'lightcyan': 'e0ffff',
  755. 'lightgoldenrodyellow': 'fafad2',
  756. 'lightgray': 'd3d3d3',
  757. 'lightgrey': 'd3d3d3',
  758. 'lightgreen': '90ee90',
  759. 'lightpink': 'ffb6c1',
  760. 'lightsalmon': 'ffa07a',
  761. 'lightseagreen': '20b2aa',
  762. 'lightskyblue': '87cefa',
  763. 'lightslategray': '789',
  764. 'lightslategrey': '789',
  765. 'lightsteelblue': 'b0c4de',
  766. 'lightyellow': 'ffffe0',
  767. 'lime': '0f0',
  768. 'limegreen': '32cd32',
  769. 'linen': 'faf0e6',
  770. 'magenta': 'f0f',
  771. 'maroon': '800000',
  772. 'mediumaquamarine': '66cdaa',
  773. 'mediumblue': '0000cd',
  774. 'mediumorchid': 'ba55d3',
  775. 'mediumpurple': '9370db',
  776. 'mediumseagreen': '3cb371',
  777. 'mediumslateblue': '7b68ee',
  778. 'mediumspringgreen': '00fa9a',
  779. 'mediumturquoise': '48d1cc',
  780. 'mediumvioletred': 'c71585',
  781. 'midnightblue': '191970',
  782. 'mintcream': 'f5fffa',
  783. 'mistyrose': 'ffe4e1',
  784. 'moccasin': 'ffe4b5',
  785. 'navajowhite': 'ffdead',
  786. 'navy': '000080',
  787. 'oldlace': 'fdf5e6',
  788. 'olive': '808000',
  789. 'olivedrab': '6b8e23',
  790. 'orange': 'ffa500',
  791. 'orangered': 'ff4500',
  792. 'orchid': 'da70d6',
  793. 'palegoldenrod': 'eee8aa',
  794. 'palegreen': '98fb98',
  795. 'paleturquoise': 'afeeee',
  796. 'palevioletred': 'db7093',
  797. 'papayawhip': 'ffefd5',
  798. 'peachpuff': 'ffdab9',
  799. 'peru': 'cd853f',
  800. 'pink': 'ffc0cb',
  801. 'plum': 'dda0dd',
  802. 'powderblue': 'b0e0e6',
  803. 'purple': '800080',
  804. 'rebeccapurple': '639',
  805. 'red': 'f00',
  806. 'rosybrown': 'bc8f8f',
  807. 'royalblue': '4169e1',
  808. 'saddlebrown': '8b4513',
  809. 'salmon': 'fa8072',
  810. 'sandybrown': 'f4a460',
  811. 'seagreen': '2e8b57',
  812. 'seashell': 'fff5ee',
  813. 'sienna': 'a0522d',
  814. 'silver': 'c0c0c0',
  815. 'skyblue': '87ceeb',
  816. 'slateblue': '6a5acd',
  817. 'slategray': '708090',
  818. 'slategrey': '708090',
  819. 'snow': 'fffafa',
  820. 'springgreen': '00ff7f',
  821. 'steelblue': '4682b4',
  822. 'tan': 'd2b48c',
  823. 'teal': '008080',
  824. 'thistle': 'd8bfd8',
  825. 'tomato': 'ff6347',
  826. 'turquoise': '40e0d0',
  827. 'violet': 'ee82ee',
  828. 'wheat': 'f5deb3',
  829. 'white': 'fff',
  830. 'whitesmoke': 'f5f5f5',
  831. 'yellow': 'ff0',
  832. 'yellowgreen': '9acd32'
  833. };
  834. var HEX_TO_NAME = {
  835. '800000': 'maroon',
  836. '800080': 'purple',
  837. '808000': 'olive',
  838. '808080': 'gray',
  839. '00ffff': 'cyan',
  840. 'f0ffff': 'azure',
  841. 'f5f5dc': 'beige',
  842. 'ffe4c4': 'bisque',
  843. '000000': 'black',
  844. '0000ff': 'blue',
  845. 'a52a2a': 'brown',
  846. 'ff7f50': 'coral',
  847. 'ffd700': 'gold',
  848. '008000': 'green',
  849. '4b0082': 'indigo',
  850. 'fffff0': 'ivory',
  851. 'f0e68c': 'khaki',
  852. '00ff00': 'lime',
  853. 'faf0e6': 'linen',
  854. '000080': 'navy',
  855. 'ffa500': 'orange',
  856. 'da70d6': 'orchid',
  857. 'cd853f': 'peru',
  858. 'ffc0cb': 'pink',
  859. 'dda0dd': 'plum',
  860. 'f00': 'red',
  861. 'ff0000': 'red',
  862. 'fa8072': 'salmon',
  863. 'a0522d': 'sienna',
  864. 'c0c0c0': 'silver',
  865. 'fffafa': 'snow',
  866. 'd2b48c': 'tan',
  867. '008080': 'teal',
  868. 'ff6347': 'tomato',
  869. 'ee82ee': 'violet',
  870. 'f5deb3': 'wheat',
  871. 'ffffff': 'white',
  872. 'ffff00': 'yellow'
  873. };
  874. function hueToRgb(p, q, t) {
  875. if (t < 0) {
  876. t += 1;
  877. }
  878. if (t > 1) {
  879. t -= 1;
  880. }
  881. if (t < 1 / 6) {
  882. return p + (q - p) * 6 * t;
  883. }
  884. if (t < 1 / 2) {
  885. return q;
  886. }
  887. if (t < 2 / 3) {
  888. return p + (q - p) * (2 / 3 - t) * 6;
  889. }
  890. return p;
  891. }
  892. function hslToRgb(h, s, l, a) {
  893. var r;
  894. var g;
  895. var b;
  896. if (s === 0) {
  897. r = g = b = l; // achromatic
  898. } else {
  899. var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  900. var p = 2 * l - q;
  901. r = hueToRgb(p, q, h + 1 / 3);
  902. g = hueToRgb(p, q, h);
  903. b = hueToRgb(p, q, h - 1 / 3);
  904. }
  905. return [
  906. Math.round(r * 255),
  907. Math.round(g * 255),
  908. Math.round(b * 255),
  909. a
  910. ];
  911. }
  912. function toHex(value) {
  913. value = value.toString(16);
  914. return value.length === 1 ? '0' + value : value;
  915. }
  916. function parseFunctionArgs(functionArgs, count, rgb) {
  917. var cursor = functionArgs.head;
  918. var args = [];
  919. var wasValue = false;
  920. while (cursor !== null) {
  921. var node = cursor.data;
  922. var type = node.type;
  923. switch (type) {
  924. case 'Number':
  925. case 'Percentage':
  926. if (wasValue) {
  927. return;
  928. }
  929. wasValue = true;
  930. args.push({
  931. type: type,
  932. value: Number(node.value)
  933. });
  934. break;
  935. case 'Operator':
  936. if (node.value === ',') {
  937. if (!wasValue) {
  938. return;
  939. }
  940. wasValue = false;
  941. } else if (wasValue || node.value !== '+') {
  942. return;
  943. }
  944. break;
  945. default:
  946. // something we couldn't understand
  947. return;
  948. }
  949. cursor = cursor.next;
  950. }
  951. if (args.length !== count) {
  952. // invalid arguments count
  953. // TODO: remove those tokens
  954. return;
  955. }
  956. if (args.length === 4) {
  957. if (args[3].type !== 'Number') {
  958. // 4th argument should be a number
  959. // TODO: remove those tokens
  960. return;
  961. }
  962. args[3].type = 'Alpha';
  963. }
  964. if (rgb) {
  965. if (args[0].type !== args[1].type || args[0].type !== args[2].type) {
  966. // invalid color, numbers and percentage shouldn't be mixed
  967. // TODO: remove those tokens
  968. return;
  969. }
  970. } else {
  971. if (args[0].type !== 'Number' ||
  972. args[1].type !== 'Percentage' ||
  973. args[2].type !== 'Percentage') {
  974. // invalid color, for hsl values should be: number, percentage, percentage
  975. // TODO: remove those tokens
  976. return;
  977. }
  978. args[0].type = 'Angle';
  979. }
  980. return args.map(function(arg) {
  981. var value = Math.max(0, arg.value);
  982. switch (arg.type) {
  983. case 'Number':
  984. // fit value to [0..255] range
  985. value = Math.min(value, 255);
  986. break;
  987. case 'Percentage':
  988. // convert 0..100% to value in [0..255] range
  989. value = Math.min(value, 100) / 100;
  990. if (!rgb) {
  991. return value;
  992. }
  993. value = 255 * value;
  994. break;
  995. case 'Angle':
  996. // fit value to (-360..360) range
  997. return (((value % 360) + 360) % 360) / 360;
  998. case 'Alpha':
  999. // fit value to [0..1] range
  1000. return Math.min(value, 1);
  1001. }
  1002. return Math.round(value);
  1003. });
  1004. }
  1005. function compressFunction(node, item, list) {
  1006. var functionName = node.name;
  1007. var args;
  1008. if (functionName === 'rgba' || functionName === 'hsla') {
  1009. args = parseFunctionArgs(node.children, 4, functionName === 'rgba');
  1010. if (!args) {
  1011. // something went wrong
  1012. return;
  1013. }
  1014. if (functionName === 'hsla') {
  1015. args = hslToRgb.apply(null, args);
  1016. node.name = 'rgba';
  1017. }
  1018. if (args[3] === 0) {
  1019. // try to replace `rgba(x, x, x, 0)` to `transparent`
  1020. // always replace `rgba(0, 0, 0, 0)` to `transparent`
  1021. // otherwise avoid replacement in gradients since it may break color transition
  1022. // http://stackoverflow.com/questions/11829410/css3-gradient-rendering-issues-from-transparent-to-white
  1023. var scopeFunctionName = this.function && this.function.name;
  1024. if ((args[0] === 0 && args[1] === 0 && args[2] === 0) ||
  1025. !/^(?:to|from|color-stop)$|gradient$/i.test(scopeFunctionName)) {
  1026. item.data = {
  1027. type: 'Identifier',
  1028. loc: node.loc,
  1029. name: 'transparent'
  1030. };
  1031. return;
  1032. }
  1033. }
  1034. if (args[3] !== 1) {
  1035. // replace argument values for normalized/interpolated
  1036. node.children.each(function(node, item, list) {
  1037. if (node.type === 'Operator') {
  1038. if (node.value !== ',') {
  1039. list.remove(item);
  1040. }
  1041. return;
  1042. }
  1043. item.data = {
  1044. type: 'Number',
  1045. loc: node.loc,
  1046. value: packNumber$3(args.shift(), null)
  1047. };
  1048. });
  1049. return;
  1050. }
  1051. // otherwise convert to rgb, i.e. rgba(255, 0, 0, 1) -> rgb(255, 0, 0)
  1052. functionName = 'rgb';
  1053. }
  1054. if (functionName === 'hsl') {
  1055. args = args || parseFunctionArgs(node.children, 3, false);
  1056. if (!args) {
  1057. // something went wrong
  1058. return;
  1059. }
  1060. // convert to rgb
  1061. args = hslToRgb.apply(null, args);
  1062. functionName = 'rgb';
  1063. }
  1064. if (functionName === 'rgb') {
  1065. args = args || parseFunctionArgs(node.children, 3, true);
  1066. if (!args) {
  1067. // something went wrong
  1068. return;
  1069. }
  1070. // check if color is not at the end and not followed by space
  1071. var next = item.next;
  1072. if (next && next.data.type !== 'WhiteSpace') {
  1073. list.insert(list.createItem({
  1074. type: 'WhiteSpace',
  1075. value: ' '
  1076. }), next);
  1077. }
  1078. item.data = {
  1079. type: 'Hash',
  1080. loc: node.loc,
  1081. value: toHex(args[0]) + toHex(args[1]) + toHex(args[2])
  1082. };
  1083. compressHex(item.data, item);
  1084. }
  1085. }
  1086. function compressIdent(node, item) {
  1087. if (this.declaration === null) {
  1088. return;
  1089. }
  1090. var color = node.name.toLowerCase();
  1091. if (NAME_TO_HEX.hasOwnProperty(color) &&
  1092. lexer$1.matchDeclaration(this.declaration).isType(node, 'color')) {
  1093. var hex = NAME_TO_HEX[color];
  1094. if (hex.length + 1 <= color.length) {
  1095. // replace for shorter hex value
  1096. item.data = {
  1097. type: 'Hash',
  1098. loc: node.loc,
  1099. value: hex
  1100. };
  1101. } else {
  1102. // special case for consistent colors
  1103. if (color === 'grey') {
  1104. color = 'gray';
  1105. }
  1106. // just replace value for lower cased name
  1107. node.name = color;
  1108. }
  1109. }
  1110. }
  1111. function compressHex(node, item) {
  1112. var color = node.value.toLowerCase();
  1113. // #112233 -> #123
  1114. if (color.length === 6 &&
  1115. color[0] === color[1] &&
  1116. color[2] === color[3] &&
  1117. color[4] === color[5]) {
  1118. color = color[0] + color[2] + color[4];
  1119. }
  1120. if (HEX_TO_NAME[color]) {
  1121. item.data = {
  1122. type: 'Identifier',
  1123. loc: node.loc,
  1124. name: HEX_TO_NAME[color]
  1125. };
  1126. } else {
  1127. node.value = color;
  1128. }
  1129. }
  1130. var color = {
  1131. compressFunction: compressFunction,
  1132. compressIdent: compressIdent,
  1133. compressHex: compressHex
  1134. };
  1135. var walk$2 = csstree_min.walk;
  1136. var handlers$2 = {
  1137. Atrule: Atrule$1,
  1138. AttributeSelector: AttributeSelector,
  1139. Value: Value,
  1140. Dimension: Dimension,
  1141. Percentage: Percentage,
  1142. Number: _Number,
  1143. String: _String,
  1144. Url: Url,
  1145. Hash: color.compressHex,
  1146. Identifier: color.compressIdent,
  1147. Function: color.compressFunction
  1148. };
  1149. var replace = function(ast) {
  1150. walk$2(ast, {
  1151. leave: function(node, item, list) {
  1152. if (handlers$2.hasOwnProperty(node.type)) {
  1153. handlers$2[node.type].call(this, node, item, list);
  1154. }
  1155. }
  1156. });
  1157. };
  1158. var generate = csstree_min.generate;
  1159. function Index() {
  1160. this.seed = 0;
  1161. this.map = Object.create(null);
  1162. }
  1163. Index.prototype.resolve = function(str) {
  1164. var index = this.map[str];
  1165. if (!index) {
  1166. index = ++this.seed;
  1167. this.map[str] = index;
  1168. }
  1169. return index;
  1170. };
  1171. var createDeclarationIndexer = function createDeclarationIndexer() {
  1172. var ids = new Index();
  1173. return function markDeclaration(node) {
  1174. var id = generate(node);
  1175. node.id = ids.resolve(id);
  1176. node.length = id.length;
  1177. node.fingerprint = null;
  1178. return node;
  1179. };
  1180. };
  1181. var specificity = function specificity(simpleSelector) {
  1182. var A = 0;
  1183. var B = 0;
  1184. var C = 0;
  1185. simpleSelector.children.each(function walk(node) {
  1186. switch (node.type) {
  1187. case 'SelectorList':
  1188. case 'Selector':
  1189. node.children.each(walk);
  1190. break;
  1191. case 'IdSelector':
  1192. A++;
  1193. break;
  1194. case 'ClassSelector':
  1195. case 'AttributeSelector':
  1196. B++;
  1197. break;
  1198. case 'PseudoClassSelector':
  1199. switch (node.name.toLowerCase()) {
  1200. case 'not':
  1201. node.children.each(walk);
  1202. break;
  1203. case 'before':
  1204. case 'after':
  1205. case 'first-line':
  1206. case 'first-letter':
  1207. C++;
  1208. break;
  1209. // TODO: support for :nth-*(.. of <SelectorList>), :matches(), :has()
  1210. default:
  1211. B++;
  1212. }
  1213. break;
  1214. case 'PseudoElementSelector':
  1215. C++;
  1216. break;
  1217. case 'TypeSelector':
  1218. // ignore universal selector
  1219. if (node.name.charAt(node.name.length - 1) !== '*') {
  1220. C++;
  1221. }
  1222. break;
  1223. }
  1224. });
  1225. return [A, B, C];
  1226. };
  1227. var generate$1 = csstree_min.generate;
  1228. var nonFreezePseudoElements = {
  1229. 'first-letter': true,
  1230. 'first-line': true,
  1231. 'after': true,
  1232. 'before': true
  1233. };
  1234. var nonFreezePseudoClasses = {
  1235. 'link': true,
  1236. 'visited': true,
  1237. 'hover': true,
  1238. 'active': true,
  1239. 'first-letter': true,
  1240. 'first-line': true,
  1241. 'after': true,
  1242. 'before': true
  1243. };
  1244. var processSelector = function freeze(node, usageData) {
  1245. var pseudos = Object.create(null);
  1246. var hasPseudo = false;
  1247. node.prelude.children.each(function(simpleSelector) {
  1248. var tagName = '*';
  1249. var scope = 0;
  1250. simpleSelector.children.each(function(node) {
  1251. switch (node.type) {
  1252. case 'ClassSelector':
  1253. if (usageData && usageData.scopes) {
  1254. var classScope = usageData.scopes[node.name] || 0;
  1255. if (scope !== 0 && classScope !== scope) {
  1256. throw new Error('Selector can\'t has classes from different scopes: ' + generate$1(simpleSelector));
  1257. }
  1258. scope = classScope;
  1259. }
  1260. break;
  1261. case 'PseudoClassSelector':
  1262. var name = node.name.toLowerCase();
  1263. if (!nonFreezePseudoClasses.hasOwnProperty(name)) {
  1264. pseudos[':' + name] = true;
  1265. hasPseudo = true;
  1266. }
  1267. break;
  1268. case 'PseudoElementSelector':
  1269. var name = node.name.toLowerCase();
  1270. if (!nonFreezePseudoElements.hasOwnProperty(name)) {
  1271. pseudos['::' + name] = true;
  1272. hasPseudo = true;
  1273. }
  1274. break;
  1275. case 'TypeSelector':
  1276. tagName = node.name.toLowerCase();
  1277. break;
  1278. case 'AttributeSelector':
  1279. if (node.flags) {
  1280. pseudos['[' + node.flags.toLowerCase() + ']'] = true;
  1281. hasPseudo = true;
  1282. }
  1283. break;
  1284. case 'WhiteSpace':
  1285. case 'Combinator':
  1286. tagName = '*';
  1287. break;
  1288. }
  1289. });
  1290. simpleSelector.compareMarker = specificity(simpleSelector).toString();
  1291. simpleSelector.id = null; // pre-init property to avoid multiple hidden class
  1292. simpleSelector.id = generate$1(simpleSelector);
  1293. if (scope) {
  1294. simpleSelector.compareMarker += ':' + scope;
  1295. }
  1296. if (tagName !== '*') {
  1297. simpleSelector.compareMarker += ',' + tagName;
  1298. }
  1299. });
  1300. // add property to all rule nodes to avoid multiple hidden class
  1301. node.pseudoSignature = hasPseudo && Object.keys(pseudos).sort().join(',');
  1302. };
  1303. var resolveKeyword$2 = csstree_min.keyword;
  1304. var walk$3 = csstree_min.walk;
  1305. var generate$2 = csstree_min.generate;
  1306. var prepare = function prepare(ast, options) {
  1307. var markDeclaration = createDeclarationIndexer();
  1308. walk$3(ast, {
  1309. visit: 'Rule',
  1310. enter: function processRule(node) {
  1311. node.block.children.each(markDeclaration);
  1312. processSelector(node, options.usage);
  1313. }
  1314. });
  1315. walk$3(ast, {
  1316. visit: 'Atrule',
  1317. enter: function(node) {
  1318. if (node.prelude) {
  1319. node.prelude.id = null; // pre-init property to avoid multiple hidden class for generate
  1320. node.prelude.id = generate$2(node.prelude);
  1321. }
  1322. // compare keyframe selectors by its values
  1323. // NOTE: still no clarification about problems with keyframes selector grouping (issue #197)
  1324. if (resolveKeyword$2(node.name).basename === 'keyframes') {
  1325. node.block.avoidRulesMerge = true; /* probably we don't need to prevent those merges for @keyframes
  1326. TODO: need to be checked */
  1327. node.block.children.each(function(rule) {
  1328. rule.prelude.children.each(function(simpleselector) {
  1329. simpleselector.compareMarker = simpleselector.id;
  1330. });
  1331. });
  1332. }
  1333. }
  1334. });
  1335. return {
  1336. declaration: markDeclaration
  1337. };
  1338. };
  1339. var List$1 = csstree_min.List;
  1340. var resolveKeyword$3 = csstree_min.keyword;
  1341. var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
  1342. var walk$4 = csstree_min.walk;
  1343. function addRuleToMap(map, item, list, single) {
  1344. var node = item.data;
  1345. var name = resolveKeyword$3(node.name).basename;
  1346. var id = node.name.toLowerCase() + '/' + (node.prelude ? node.prelude.id : null);
  1347. if (!hasOwnProperty$2.call(map, name)) {
  1348. map[name] = Object.create(null);
  1349. }
  1350. if (single) {
  1351. delete map[name][id];
  1352. }
  1353. if (!hasOwnProperty$2.call(map[name], id)) {
  1354. map[name][id] = new List$1();
  1355. }
  1356. map[name][id].append(list.remove(item));
  1357. }
  1358. function relocateAtrules(ast, options) {
  1359. var collected = Object.create(null);
  1360. var topInjectPoint = null;
  1361. ast.children.each(function(node, item, list) {
  1362. if (node.type === 'Atrule') {
  1363. var name = resolveKeyword$3(node.name).basename;
  1364. switch (name) {
  1365. case 'keyframes':
  1366. addRuleToMap(collected, item, list, true);
  1367. return;
  1368. case 'media':
  1369. if (options.forceMediaMerge) {
  1370. addRuleToMap(collected, item, list, false);
  1371. return;
  1372. }
  1373. break;
  1374. }
  1375. if (topInjectPoint === null &&
  1376. name !== 'charset' &&
  1377. name !== 'import') {
  1378. topInjectPoint = item;
  1379. }
  1380. } else {
  1381. if (topInjectPoint === null) {
  1382. topInjectPoint = item;
  1383. }
  1384. }
  1385. });
  1386. for (var atrule in collected) {
  1387. for (var id in collected[atrule]) {
  1388. ast.children.insertList(
  1389. collected[atrule][id],
  1390. atrule === 'media' ? null : topInjectPoint
  1391. );
  1392. }
  1393. }
  1394. }
  1395. function isMediaRule(node) {
  1396. return node.type === 'Atrule' && node.name === 'media';
  1397. }
  1398. function processAtrule(node, item, list) {
  1399. if (!isMediaRule(node)) {
  1400. return;
  1401. }
  1402. var prev = item.prev && item.prev.data;
  1403. if (!prev || !isMediaRule(prev)) {
  1404. return;
  1405. }
  1406. // merge @media with same query
  1407. if (node.prelude &&
  1408. prev.prelude &&
  1409. node.prelude.id === prev.prelude.id) {
  1410. prev.block.children.appendList(node.block.children);
  1411. list.remove(item);
  1412. // TODO: use it when we can refer to several points in source
  1413. // prev.loc = {
  1414. // primary: prev.loc,
  1415. // merged: node.loc
  1416. // };
  1417. }
  1418. }
  1419. var _1MergeAtrule = function rejoinAtrule(ast, options) {
  1420. relocateAtrules(ast, options);
  1421. walk$4(ast, {
  1422. visit: 'Atrule',
  1423. reverse: true,
  1424. enter: processAtrule
  1425. });
  1426. };
  1427. var hasOwnProperty$3 = Object.prototype.hasOwnProperty;
  1428. function isEqualSelectors(a, b) {
  1429. var cursor1 = a.head;
  1430. var cursor2 = b.head;
  1431. while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
  1432. cursor1 = cursor1.next;
  1433. cursor2 = cursor2.next;
  1434. }
  1435. return cursor1 === null && cursor2 === null;
  1436. }
  1437. function isEqualDeclarations(a, b) {
  1438. var cursor1 = a.head;
  1439. var cursor2 = b.head;
  1440. while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
  1441. cursor1 = cursor1.next;
  1442. cursor2 = cursor2.next;
  1443. }
  1444. return cursor1 === null && cursor2 === null;
  1445. }
  1446. function compareDeclarations(declarations1, declarations2) {
  1447. var result = {
  1448. eq: [],
  1449. ne1: [],
  1450. ne2: [],
  1451. ne2overrided: []
  1452. };
  1453. var fingerprints = Object.create(null);
  1454. var declarations2hash = Object.create(null);
  1455. for (var cursor = declarations2.head; cursor; cursor = cursor.next) {
  1456. declarations2hash[cursor.data.id] = true;
  1457. }
  1458. for (var cursor = declarations1.head; cursor; cursor = cursor.next) {
  1459. var data = cursor.data;
  1460. if (data.fingerprint) {
  1461. fingerprints[data.fingerprint] = data.important;
  1462. }
  1463. if (declarations2hash[data.id]) {
  1464. declarations2hash[data.id] = false;
  1465. result.eq.push(data);
  1466. } else {
  1467. result.ne1.push(data);
  1468. }
  1469. }
  1470. for (var cursor = declarations2.head; cursor; cursor = cursor.next) {
  1471. var data = cursor.data;
  1472. if (declarations2hash[data.id]) {
  1473. // when declarations1 has an overriding declaration, this is not a difference
  1474. // unless no !important is used on prev and !important is used on the following
  1475. if (!hasOwnProperty$3.call(fingerprints, data.fingerprint) ||
  1476. (!fingerprints[data.fingerprint] && data.important)) {
  1477. result.ne2.push(data);
  1478. }
  1479. result.ne2overrided.push(data);
  1480. }
  1481. }
  1482. return result;
  1483. }
  1484. function addSelectors(dest, source) {
  1485. source.each(function(sourceData) {
  1486. var newStr = sourceData.id;
  1487. var cursor = dest.head;
  1488. while (cursor) {
  1489. var nextStr = cursor.data.id;
  1490. if (nextStr === newStr) {
  1491. return;
  1492. }
  1493. if (nextStr > newStr) {
  1494. break;
  1495. }
  1496. cursor = cursor.next;
  1497. }
  1498. dest.insert(dest.createItem(sourceData), cursor);
  1499. });
  1500. return dest;
  1501. }
  1502. // check if simpleselectors has no equal specificity and element selector
  1503. function hasSimilarSelectors(selectors1, selectors2) {
  1504. var cursor1 = selectors1.head;
  1505. while (cursor1 !== null) {
  1506. var cursor2 = selectors2.head;
  1507. while (cursor2 !== null) {
  1508. if (cursor1.data.compareMarker === cursor2.data.compareMarker) {
  1509. return true;
  1510. }
  1511. cursor2 = cursor2.next;
  1512. }
  1513. cursor1 = cursor1.next;
  1514. }
  1515. return false;
  1516. }
  1517. // test node can't to be skipped
  1518. function unsafeToSkipNode(node) {
  1519. switch (node.type) {
  1520. case 'Rule':
  1521. // unsafe skip ruleset with selector similarities
  1522. return hasSimilarSelectors(node.prelude.children, this);
  1523. case 'Atrule':
  1524. // can skip at-rules with blocks
  1525. if (node.block) {
  1526. // unsafe skip at-rule if block contains something unsafe to skip
  1527. return node.block.children.some(unsafeToSkipNode, this);
  1528. }
  1529. break;
  1530. case 'Declaration':
  1531. return false;
  1532. }
  1533. // unsafe by default
  1534. return true;
  1535. }
  1536. var utils$1 = {
  1537. isEqualSelectors: isEqualSelectors,
  1538. isEqualDeclarations: isEqualDeclarations,
  1539. compareDeclarations: compareDeclarations,
  1540. addSelectors: addSelectors,
  1541. hasSimilarSelectors: hasSimilarSelectors,
  1542. unsafeToSkipNode: unsafeToSkipNode
  1543. };
  1544. var walk$5 = csstree_min.walk;
  1545. function processRule(node, item, list) {
  1546. var selectors = node.prelude.children;
  1547. var declarations = node.block.children;
  1548. list.prevUntil(item.prev, function(prev) {
  1549. // skip non-ruleset node if safe
  1550. if (prev.type !== 'Rule') {
  1551. return utils$1.unsafeToSkipNode.call(selectors, prev);
  1552. }
  1553. var prevSelectors = prev.prelude.children;
  1554. var prevDeclarations = prev.block.children;
  1555. // try to join rulesets with equal pseudo signature
  1556. if (node.pseudoSignature === prev.pseudoSignature) {
  1557. // try to join by selectors
  1558. if (utils$1.isEqualSelectors(prevSelectors, selectors)) {
  1559. prevDeclarations.appendList(declarations);
  1560. list.remove(item);
  1561. return true;
  1562. }
  1563. // try to join by declarations
  1564. if (utils$1.isEqualDeclarations(declarations, prevDeclarations)) {
  1565. utils$1.addSelectors(prevSelectors, selectors);
  1566. list.remove(item);
  1567. return true;
  1568. }
  1569. }
  1570. // go to prev ruleset if has no selector similarities
  1571. return utils$1.hasSimilarSelectors(selectors, prevSelectors);
  1572. });
  1573. }
  1574. // NOTE: direction should be left to right, since rulesets merge to left
  1575. // ruleset. When direction right to left unmerged rulesets may prevent lookup
  1576. // TODO: remove initial merge
  1577. var _2InitialMergeRuleset = function initialMergeRule(ast) {
  1578. walk$5(ast, {
  1579. visit: 'Rule',
  1580. enter: processRule
  1581. });
  1582. };
  1583. var List$2 = csstree_min.List;
  1584. var walk$6 = csstree_min.walk;
  1585. function processRule$1(node, item, list) {
  1586. var selectors = node.prelude.children;
  1587. // generate new rule sets:
  1588. // .a, .b { color: red; }
  1589. // ->
  1590. // .a { color: red; }
  1591. // .b { color: red; }
  1592. // while there are more than 1 simple selector split for rulesets
  1593. while (selectors.head !== selectors.tail) {
  1594. var newSelectors = new List$2();
  1595. newSelectors.insert(selectors.remove(selectors.head));
  1596. list.insert(list.createItem({
  1597. type: 'Rule',
  1598. loc: node.loc,
  1599. prelude: {
  1600. type: 'SelectorList',
  1601. loc: node.prelude.loc,
  1602. children: newSelectors
  1603. },
  1604. block: {
  1605. type: 'Block',
  1606. loc: node.block.loc,
  1607. children: node.block.children.copy()
  1608. },
  1609. pseudoSignature: node.pseudoSignature
  1610. }), item);
  1611. }
  1612. }
  1613. var _3DisjoinRuleset = function disjoinRule(ast) {
  1614. walk$6(ast, {
  1615. visit: 'Rule',
  1616. reverse: true,
  1617. enter: processRule$1
  1618. });
  1619. };
  1620. var List$3 = csstree_min.List;
  1621. var generate$3 = csstree_min.generate;
  1622. var walk$7 = csstree_min.walk;
  1623. var REPLACE = 1;
  1624. var REMOVE = 2;
  1625. var TOP = 0;
  1626. var RIGHT = 1;
  1627. var BOTTOM = 2;
  1628. var LEFT = 3;
  1629. var SIDES = ['top', 'right', 'bottom', 'left'];
  1630. var SIDE = {
  1631. 'margin-top': 'top',
  1632. 'margin-right': 'right',
  1633. 'margin-bottom': 'bottom',
  1634. 'margin-left': 'left',
  1635. 'padding-top': 'top',
  1636. 'padding-right': 'right',
  1637. 'padding-bottom': 'bottom',
  1638. 'padding-left': 'left',
  1639. 'border-top-color': 'top',
  1640. 'border-right-color': 'right',
  1641. 'border-bottom-color': 'bottom',
  1642. 'border-left-color': 'left',
  1643. 'border-top-width': 'top',
  1644. 'border-right-width': 'right',
  1645. 'border-bottom-width': 'bottom',
  1646. 'border-left-width': 'left',
  1647. 'border-top-style': 'top',
  1648. 'border-right-style': 'right',
  1649. 'border-bottom-style': 'bottom',
  1650. 'border-left-style': 'left'
  1651. };
  1652. var MAIN_PROPERTY = {
  1653. 'margin': 'margin',
  1654. 'margin-top': 'margin',
  1655. 'margin-right': 'margin',
  1656. 'margin-bottom': 'margin',
  1657. 'margin-left': 'margin',
  1658. 'padding': 'padding',
  1659. 'padding-top': 'padding',
  1660. 'padding-right': 'padding',
  1661. 'padding-bottom': 'padding',
  1662. 'padding-left': 'padding',
  1663. 'border-color': 'border-color',
  1664. 'border-top-color': 'border-color',
  1665. 'border-right-color': 'border-color',
  1666. 'border-bottom-color': 'border-color',
  1667. 'border-left-color': 'border-color',
  1668. 'border-width': 'border-width',
  1669. 'border-top-width': 'border-width',
  1670. 'border-right-width': 'border-width',
  1671. 'border-bottom-width': 'border-width',
  1672. 'border-left-width': 'border-width',
  1673. 'border-style': 'border-style',
  1674. 'border-top-style': 'border-style',
  1675. 'border-right-style': 'border-style',
  1676. 'border-bottom-style': 'border-style',
  1677. 'border-left-style': 'border-style'
  1678. };
  1679. function TRBL(name) {
  1680. this.name = name;
  1681. this.loc = null;
  1682. this.iehack = undefined;
  1683. this.sides = {
  1684. 'top': null,
  1685. 'right': null,
  1686. 'bottom': null,
  1687. 'left': null
  1688. };
  1689. }
  1690. TRBL.prototype.getValueSequence = function(declaration, count) {
  1691. var values = [];
  1692. var iehack = '';
  1693. var hasBadValues = declaration.value.type !== 'Value' || declaration.value.children.some(function(child) {
  1694. var special = false;
  1695. switch (child.type) {
  1696. case 'Identifier':
  1697. switch (child.name) {
  1698. case '\\0':
  1699. case '\\9':
  1700. iehack = child.name;
  1701. return;
  1702. case 'inherit':
  1703. case 'initial':
  1704. case 'unset':
  1705. case 'revert':
  1706. special = child.name;
  1707. break;
  1708. }
  1709. break;
  1710. case 'Dimension':
  1711. switch (child.unit) {
  1712. // is not supported until IE11
  1713. case 'rem':
  1714. // v* units is too buggy across browsers and better
  1715. // don't merge values with those units
  1716. case 'vw':
  1717. case 'vh':
  1718. case 'vmin':
  1719. case 'vmax':
  1720. case 'vm': // IE9 supporting "vm" instead of "vmin".
  1721. special = child.unit;
  1722. break;
  1723. }
  1724. break;
  1725. case 'Hash': // color
  1726. case 'Number':
  1727. case 'Percentage':
  1728. break;
  1729. case 'Function':
  1730. if (child.name === 'var') {
  1731. return true;
  1732. }
  1733. special = child.name;
  1734. break;
  1735. case 'WhiteSpace':
  1736. return false; // ignore space
  1737. default:
  1738. return true; // bad value
  1739. }
  1740. values.push({
  1741. node: child,
  1742. special: special,
  1743. important: declaration.important
  1744. });
  1745. });
  1746. if (hasBadValues || values.length > count) {
  1747. return false;
  1748. }
  1749. if (typeof this.iehack === 'string' && this.iehack !== iehack) {
  1750. return false;
  1751. }
  1752. this.iehack = iehack; // move outside
  1753. return values;
  1754. };
  1755. TRBL.prototype.canOverride = function(side, value) {
  1756. var currentValue = this.sides[side];
  1757. return !currentValue || (value.important && !currentValue.important);
  1758. };
  1759. TRBL.prototype.add = function(name, declaration) {
  1760. function attemptToAdd() {
  1761. var sides = this.sides;
  1762. var side = SIDE[name];
  1763. if (side) {
  1764. if (side in sides === false) {
  1765. return false;
  1766. }
  1767. var values = this.getValueSequence(declaration, 1);
  1768. if (!values || !values.length) {
  1769. return false;
  1770. }
  1771. // can mix only if specials are equal
  1772. for (var key in sides) {
  1773. if (sides[key] !== null && sides[key].special !== values[0].special) {
  1774. return false;
  1775. }
  1776. }
  1777. if (!this.canOverride(side, values[0])) {
  1778. return true;
  1779. }
  1780. sides[side] = values[0];
  1781. return true;
  1782. } else if (name === this.name) {
  1783. var values = this.getValueSequence(declaration, 4);
  1784. if (!values || !values.length) {
  1785. return false;
  1786. }
  1787. switch (values.length) {
  1788. case 1:
  1789. values[RIGHT] = values[TOP];
  1790. values[BOTTOM] = values[TOP];
  1791. values[LEFT] = values[TOP];
  1792. break;
  1793. case 2:
  1794. values[BOTTOM] = values[TOP];
  1795. values[LEFT] = values[RIGHT];
  1796. break;
  1797. case 3:
  1798. values[LEFT] = values[RIGHT];
  1799. break;
  1800. }
  1801. // can mix only if specials are equal
  1802. for (var i = 0; i < 4; i++) {
  1803. for (var key in sides) {
  1804. if (sides[key] !== null && sides[key].special !== values[i].special) {
  1805. return false;
  1806. }
  1807. }
  1808. }
  1809. for (var i = 0; i < 4; i++) {
  1810. if (this.canOverride(SIDES[i], values[i])) {
  1811. sides[SIDES[i]] = values[i];
  1812. }
  1813. }
  1814. return true;
  1815. }
  1816. }
  1817. if (!attemptToAdd.call(this)) {
  1818. return false;
  1819. }
  1820. // TODO: use it when we can refer to several points in source
  1821. // if (this.loc) {
  1822. // this.loc = {
  1823. // primary: this.loc,
  1824. // merged: declaration.loc
  1825. // };
  1826. // } else {
  1827. // this.loc = declaration.loc;
  1828. // }
  1829. if (!this.loc) {
  1830. this.loc = declaration.loc;
  1831. }
  1832. return true;
  1833. };
  1834. TRBL.prototype.isOkToMinimize = function() {
  1835. var top = this.sides.top;
  1836. var right = this.sides.right;
  1837. var bottom = this.sides.bottom;
  1838. var left = this.sides.left;
  1839. if (top && right && bottom && left) {
  1840. var important =
  1841. top.important +
  1842. right.important +
  1843. bottom.important +
  1844. left.important;
  1845. return important === 0 || important === 4;
  1846. }
  1847. return false;
  1848. };
  1849. TRBL.prototype.getValue = function() {
  1850. var result = new List$3();
  1851. var sides = this.sides;
  1852. var values = [
  1853. sides.top,
  1854. sides.right,
  1855. sides.bottom,
  1856. sides.left
  1857. ];
  1858. var stringValues = [
  1859. generate$3(sides.top.node),
  1860. generate$3(sides.right.node),
  1861. generate$3(sides.bottom.node),
  1862. generate$3(sides.left.node)
  1863. ];
  1864. if (stringValues[LEFT] === stringValues[RIGHT]) {
  1865. values.pop();
  1866. if (stringValues[BOTTOM] === stringValues[TOP]) {
  1867. values.pop();
  1868. if (stringValues[RIGHT] === stringValues[TOP]) {
  1869. values.pop();
  1870. }
  1871. }
  1872. }
  1873. for (var i = 0; i < values.length; i++) {
  1874. if (i) {
  1875. result.appendData({ type: 'WhiteSpace', value: ' ' });
  1876. }
  1877. result.appendData(values[i].node);
  1878. }
  1879. if (this.iehack) {
  1880. result.appendData({ type: 'WhiteSpace', value: ' ' });
  1881. result.appendData({
  1882. type: 'Identifier',
  1883. loc: null,
  1884. name: this.iehack
  1885. });
  1886. }
  1887. return {
  1888. type: 'Value',
  1889. loc: null,
  1890. children: result
  1891. };
  1892. };
  1893. TRBL.prototype.getDeclaration = function() {
  1894. return {
  1895. type: 'Declaration',
  1896. loc: this.loc,
  1897. important: this.sides.top.important,
  1898. property: this.name,
  1899. value: this.getValue()
  1900. };
  1901. };
  1902. function processRule$2(rule, shorts, shortDeclarations, lastShortSelector) {
  1903. var declarations = rule.block.children;
  1904. var selector = rule.prelude.children.first().id;
  1905. rule.block.children.eachRight(function(declaration, item) {
  1906. var property = declaration.property;
  1907. if (!MAIN_PROPERTY.hasOwnProperty(property)) {
  1908. return;
  1909. }
  1910. var key = MAIN_PROPERTY[property];
  1911. var shorthand;
  1912. var operation;
  1913. if (!lastShortSelector || selector === lastShortSelector) {
  1914. if (key in shorts) {
  1915. operation = REMOVE;
  1916. shorthand = shorts[key];
  1917. }
  1918. }
  1919. if (!shorthand || !shorthand.add(property, declaration)) {
  1920. operation = REPLACE;
  1921. shorthand = new TRBL(key);
  1922. // if can't parse value ignore it and break shorthand children
  1923. if (!shorthand.add(property, declaration)) {
  1924. lastShortSelector = null;
  1925. return;
  1926. }
  1927. }
  1928. shorts[key] = shorthand;
  1929. shortDeclarations.push({
  1930. operation: operation,
  1931. block: declarations,
  1932. item: item,
  1933. shorthand: shorthand
  1934. });
  1935. lastShortSelector = selector;
  1936. });
  1937. return lastShortSelector;
  1938. }
  1939. function processShorthands(shortDeclarations, markDeclaration) {
  1940. shortDeclarations.forEach(function(item) {
  1941. var shorthand = item.shorthand;
  1942. if (!shorthand.isOkToMinimize()) {
  1943. return;
  1944. }
  1945. if (item.operation === REPLACE) {
  1946. item.item.data = markDeclaration(shorthand.getDeclaration());
  1947. } else {
  1948. item.block.remove(item.item);
  1949. }
  1950. });
  1951. }
  1952. var _4RestructShorthand = function restructBlock(ast, indexer) {
  1953. var stylesheetMap = {};
  1954. var shortDeclarations = [];
  1955. walk$7(ast, {
  1956. visit: 'Rule',
  1957. reverse: true,
  1958. enter: function(node) {
  1959. var stylesheet = this.block || this.stylesheet;
  1960. var ruleId = (node.pseudoSignature || '') + '|' + node.prelude.children.first().id;
  1961. var ruleMap;
  1962. var shorts;
  1963. if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
  1964. ruleMap = {
  1965. lastShortSelector: null
  1966. };
  1967. stylesheetMap[stylesheet.id] = ruleMap;
  1968. } else {
  1969. ruleMap = stylesheetMap[stylesheet.id];
  1970. }
  1971. if (ruleMap.hasOwnProperty(ruleId)) {
  1972. shorts = ruleMap[ruleId];
  1973. } else {
  1974. shorts = {};
  1975. ruleMap[ruleId] = shorts;
  1976. }
  1977. ruleMap.lastShortSelector = processRule$2.call(this, node, shorts, shortDeclarations, ruleMap.lastShortSelector);
  1978. }
  1979. });
  1980. processShorthands(shortDeclarations, indexer.declaration);
  1981. };
  1982. var resolveProperty = csstree_min.property;
  1983. var resolveKeyword$4 = csstree_min.keyword;
  1984. var walk$8 = csstree_min.walk;
  1985. var generate$4 = csstree_min.generate;
  1986. var fingerprintId = 1;
  1987. var dontRestructure = {
  1988. 'src': 1 // https://github.com/afelix/csso/issues/50
  1989. };
  1990. var DONT_MIX_VALUE = {
  1991. // https://developer.mozilla.org/en-US/docs/Web/CSS/display#Browser_compatibility
  1992. 'display': /table|ruby|flex|-(flex)?box$|grid|contents|run-in/i,
  1993. // https://developer.mozilla.org/en/docs/Web/CSS/text-align
  1994. 'text-align': /^(start|end|match-parent|justify-all)$/i
  1995. };
  1996. var SAFE_VALUES = {
  1997. cursor: [
  1998. 'auto', 'crosshair', 'default', 'move', 'text', 'wait', 'help',
  1999. 'n-resize', 'e-resize', 's-resize', 'w-resize',
  2000. 'ne-resize', 'nw-resize', 'se-resize', 'sw-resize',
  2001. 'pointer', 'progress', 'not-allowed', 'no-drop', 'vertical-text', 'all-scroll',
  2002. 'col-resize', 'row-resize'
  2003. ],
  2004. overflow: [
  2005. 'hidden', 'visible', 'scroll', 'auto'
  2006. ],
  2007. position: [
  2008. 'static', 'relative', 'absolute', 'fixed'
  2009. ]
  2010. };
  2011. var NEEDLESS_TABLE = {
  2012. 'border-width': ['border'],
  2013. 'border-style': ['border'],
  2014. 'border-color': ['border'],
  2015. 'border-top': ['border'],
  2016. 'border-right': ['border'],
  2017. 'border-bottom': ['border'],
  2018. 'border-left': ['border'],
  2019. 'border-top-width': ['border-top', 'border-width', 'border'],
  2020. 'border-right-width': ['border-right', 'border-width', 'border'],
  2021. 'border-bottom-width': ['border-bottom', 'border-width', 'border'],
  2022. 'border-left-width': ['border-left', 'border-width', 'border'],
  2023. 'border-top-style': ['border-top', 'border-style', 'border'],
  2024. 'border-right-style': ['border-right', 'border-style', 'border'],
  2025. 'border-bottom-style': ['border-bottom', 'border-style', 'border'],
  2026. 'border-left-style': ['border-left', 'border-style', 'border'],
  2027. 'border-top-color': ['border-top', 'border-color', 'border'],
  2028. 'border-right-color': ['border-right', 'border-color', 'border'],
  2029. 'border-bottom-color': ['border-bottom', 'border-color', 'border'],
  2030. 'border-left-color': ['border-left', 'border-color', 'border'],
  2031. 'margin-top': ['margin'],
  2032. 'margin-right': ['margin'],
  2033. 'margin-bottom': ['margin'],
  2034. 'margin-left': ['margin'],
  2035. 'padding-top': ['padding'],
  2036. 'padding-right': ['padding'],
  2037. 'padding-bottom': ['padding'],
  2038. 'padding-left': ['padding'],
  2039. 'font-style': ['font'],
  2040. 'font-variant': ['font'],
  2041. 'font-weight': ['font'],
  2042. 'font-size': ['font'],
  2043. 'font-family': ['font'],
  2044. 'list-style-type': ['list-style'],
  2045. 'list-style-position': ['list-style'],
  2046. 'list-style-image': ['list-style']
  2047. };
  2048. function getPropertyFingerprint(propertyName, declaration, fingerprints) {
  2049. var realName = resolveProperty(propertyName).basename;
  2050. if (realName === 'background') {
  2051. return propertyName + ':' + generate$4(declaration.value);
  2052. }
  2053. var declarationId = declaration.id;
  2054. var fingerprint = fingerprints[declarationId];
  2055. if (!fingerprint) {
  2056. switch (declaration.value.type) {
  2057. case 'Value':
  2058. var vendorId = '';
  2059. var iehack = '';
  2060. var special = {};
  2061. var raw = false;
  2062. declaration.value.children.each(function walk(node) {
  2063. switch (node.type) {
  2064. case 'Value':
  2065. case 'Brackets':
  2066. case 'Parentheses':
  2067. node.children.each(walk);
  2068. break;
  2069. case 'Raw':
  2070. raw = true;
  2071. break;
  2072. case 'Identifier':
  2073. var name = node.name;
  2074. if (!vendorId) {
  2075. vendorId = resolveKeyword$4(name).vendor;
  2076. }
  2077. if (/\\[09]/.test(name)) {
  2078. iehack = RegExp.lastMatch;
  2079. }
  2080. if (SAFE_VALUES.hasOwnProperty(realName)) {
  2081. if (SAFE_VALUES[realName].indexOf(name) === -1) {
  2082. special[name] = true;
  2083. }
  2084. } else if (DONT_MIX_VALUE.hasOwnProperty(realName)) {
  2085. if (DONT_MIX_VALUE[realName].test(name)) {
  2086. special[name] = true;
  2087. }
  2088. }
  2089. break;
  2090. case 'Function':
  2091. var name = node.name;
  2092. if (!vendorId) {
  2093. vendorId = resolveKeyword$4(name).vendor;
  2094. }
  2095. if (name === 'rect') {
  2096. // there are 2 forms of rect:
  2097. // rect(<top>, <right>, <bottom>, <left>) - standart
  2098. // rect(<top> <right> <bottom> <left>) – backwards compatible syntax
  2099. // only the same form values can be merged
  2100. var hasComma = node.children.some(function(node) {
  2101. return node.type === 'Operator' && node.value === ',';
  2102. });
  2103. if (!hasComma) {
  2104. name = 'rect-backward';
  2105. }
  2106. }
  2107. special[name + '()'] = true;
  2108. // check nested tokens too
  2109. node.children.each(walk);
  2110. break;
  2111. case 'Dimension':
  2112. var unit = node.unit;
  2113. if (/\\[09]/.test(unit)) {
  2114. iehack = RegExp.lastMatch;
  2115. }
  2116. switch (unit) {
  2117. // is not supported until IE11
  2118. case 'rem':
  2119. // v* units is too buggy across browsers and better
  2120. // don't merge values with those units
  2121. case 'vw':
  2122. case 'vh':
  2123. case 'vmin':
  2124. case 'vmax':
  2125. case 'vm': // IE9 supporting "vm" instead of "vmin".
  2126. special[unit] = true;
  2127. break;
  2128. }
  2129. break;
  2130. }
  2131. });
  2132. fingerprint = raw
  2133. ? '!' + fingerprintId++
  2134. : '!' + Object.keys(special).sort() + '|' + iehack + vendorId;
  2135. break;
  2136. case 'Raw':
  2137. fingerprint = '!' + declaration.value.value;
  2138. break;
  2139. default:
  2140. fingerprint = generate$4(declaration.value);
  2141. }
  2142. fingerprints[declarationId] = fingerprint;
  2143. }
  2144. return propertyName + fingerprint;
  2145. }
  2146. function needless(props, declaration, fingerprints) {
  2147. var property = resolveProperty(declaration.property);
  2148. if (NEEDLESS_TABLE.hasOwnProperty(property.basename)) {
  2149. var table = NEEDLESS_TABLE[property.basename];
  2150. for (var i = 0; i < table.length; i++) {
  2151. var ppre = getPropertyFingerprint(property.prefix + table[i], declaration, fingerprints);
  2152. var prev = props.hasOwnProperty(ppre) ? props[ppre] : null;
  2153. if (prev && (!declaration.important || prev.item.data.important)) {
  2154. return prev;
  2155. }
  2156. }
  2157. }
  2158. }
  2159. function processRule$3(rule, item, list, props, fingerprints) {
  2160. var declarations = rule.block.children;
  2161. declarations.eachRight(function(declaration, declarationItem) {
  2162. var property = declaration.property;
  2163. var fingerprint = getPropertyFingerprint(property, declaration, fingerprints);
  2164. var prev = props[fingerprint];
  2165. if (prev && !dontRestructure.hasOwnProperty(property)) {
  2166. if (declaration.important && !prev.item.data.important) {
  2167. props[fingerprint] = {
  2168. block: declarations,
  2169. item: declarationItem
  2170. };
  2171. prev.block.remove(prev.item);
  2172. // TODO: use it when we can refer to several points in source
  2173. // declaration.loc = {
  2174. // primary: declaration.loc,
  2175. // merged: prev.item.data.loc
  2176. // };
  2177. } else {
  2178. declarations.remove(declarationItem);
  2179. // TODO: use it when we can refer to several points in source
  2180. // prev.item.data.loc = {
  2181. // primary: prev.item.data.loc,
  2182. // merged: declaration.loc
  2183. // };
  2184. }
  2185. } else {
  2186. var prev = needless(props, declaration, fingerprints);
  2187. if (prev) {
  2188. declarations.remove(declarationItem);
  2189. // TODO: use it when we can refer to several points in source
  2190. // prev.item.data.loc = {
  2191. // primary: prev.item.data.loc,
  2192. // merged: declaration.loc
  2193. // };
  2194. } else {
  2195. declaration.fingerprint = fingerprint;
  2196. props[fingerprint] = {
  2197. block: declarations,
  2198. item: declarationItem
  2199. };
  2200. }
  2201. }
  2202. });
  2203. if (declarations.isEmpty()) {
  2204. list.remove(item);
  2205. }
  2206. }
  2207. var _6RestructBlock = function restructBlock(ast) {
  2208. var stylesheetMap = {};
  2209. var fingerprints = Object.create(null);
  2210. walk$8(ast, {
  2211. visit: 'Rule',
  2212. reverse: true,
  2213. enter: function(node, item, list) {
  2214. var stylesheet = this.block || this.stylesheet;
  2215. var ruleId = (node.pseudoSignature || '') + '|' + node.prelude.children.first().id;
  2216. var ruleMap;
  2217. var props;
  2218. if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
  2219. ruleMap = {};
  2220. stylesheetMap[stylesheet.id] = ruleMap;
  2221. } else {
  2222. ruleMap = stylesheetMap[stylesheet.id];
  2223. }
  2224. if (ruleMap.hasOwnProperty(ruleId)) {
  2225. props = ruleMap[ruleId];
  2226. } else {
  2227. props = {};
  2228. ruleMap[ruleId] = props;
  2229. }
  2230. processRule$3.call(this, node, item, list, props, fingerprints);
  2231. }
  2232. });
  2233. };
  2234. var walk$9 = csstree_min.walk;
  2235. /*
  2236. At this step all rules has single simple selector. We try to join by equal
  2237. declaration blocks to first rule, e.g.
  2238. .a { color: red }
  2239. b { ... }
  2240. .b { color: red }
  2241. ->
  2242. .a, .b { color: red }
  2243. b { ... }
  2244. */
  2245. function processRule$4(node, item, list) {
  2246. var selectors = node.prelude.children;
  2247. var declarations = node.block.children;
  2248. var nodeCompareMarker = selectors.first().compareMarker;
  2249. var skippedCompareMarkers = {};
  2250. list.nextUntil(item.next, function(next, nextItem) {
  2251. // skip non-ruleset node if safe
  2252. if (next.type !== 'Rule') {
  2253. return utils$1.unsafeToSkipNode.call(selectors, next);
  2254. }
  2255. if (node.pseudoSignature !== next.pseudoSignature) {
  2256. return true;
  2257. }
  2258. var nextFirstSelector = next.prelude.children.head;
  2259. var nextDeclarations = next.block.children;
  2260. var nextCompareMarker = nextFirstSelector.data.compareMarker;
  2261. // if next ruleset has same marked as one of skipped then stop joining
  2262. if (nextCompareMarker in skippedCompareMarkers) {
  2263. return true;
  2264. }
  2265. // try to join by selectors
  2266. if (selectors.head === selectors.tail) {
  2267. if (selectors.first().id === nextFirstSelector.data.id) {
  2268. declarations.appendList(nextDeclarations);
  2269. list.remove(nextItem);
  2270. return;
  2271. }
  2272. }
  2273. // try to join by properties
  2274. if (utils$1.isEqualDeclarations(declarations, nextDeclarations)) {
  2275. var nextStr = nextFirstSelector.data.id;
  2276. selectors.some(function(data, item) {
  2277. var curStr = data.id;
  2278. if (nextStr < curStr) {
  2279. selectors.insert(nextFirstSelector, item);
  2280. return true;
  2281. }
  2282. if (!item.next) {
  2283. selectors.insert(nextFirstSelector);
  2284. return true;
  2285. }
  2286. });
  2287. list.remove(nextItem);
  2288. return;
  2289. }
  2290. // go to next ruleset if current one can be skipped (has no equal specificity nor element selector)
  2291. if (nextCompareMarker === nodeCompareMarker) {
  2292. return true;
  2293. }
  2294. skippedCompareMarkers[nextCompareMarker] = true;
  2295. });
  2296. }
  2297. var _7MergeRuleset = function mergeRule(ast) {
  2298. walk$9(ast, {
  2299. visit: 'Rule',
  2300. enter: processRule$4
  2301. });
  2302. };
  2303. var List$4 = csstree_min.List;
  2304. var walk$a = csstree_min.walk;
  2305. function calcSelectorLength(list) {
  2306. var length = 0;
  2307. list.each(function(data) {
  2308. length += data.id.length + 1;
  2309. });
  2310. return length - 1;
  2311. }
  2312. function calcDeclarationsLength(tokens) {
  2313. var length = 0;
  2314. for (var i = 0; i < tokens.length; i++) {
  2315. length += tokens[i].length;
  2316. }
  2317. return (
  2318. length + // declarations
  2319. tokens.length - 1 // delimeters
  2320. );
  2321. }
  2322. function processRule$5(node, item, list) {
  2323. var avoidRulesMerge = this.block !== null ? this.block.avoidRulesMerge : false;
  2324. var selectors = node.prelude.children;
  2325. var block = node.block;
  2326. var disallowDownMarkers = Object.create(null);
  2327. var allowMergeUp = true;
  2328. var allowMergeDown = true;
  2329. list.prevUntil(item.prev, function(prev, prevItem) {
  2330. var prevBlock = prev.block;
  2331. var prevType = prev.type;
  2332. if (prevType !== 'Rule') {
  2333. var unsafe = utils$1.unsafeToSkipNode.call(selectors, prev);
  2334. if (!unsafe && prevType === 'Atrule' && prevBlock) {
  2335. walk$a(prevBlock, {
  2336. visit: 'Rule',
  2337. enter: function(node) {
  2338. node.prelude.children.each(function(data) {
  2339. disallowDownMarkers[data.compareMarker] = true;
  2340. });
  2341. }
  2342. });
  2343. }
  2344. return unsafe;
  2345. }
  2346. var prevSelectors = prev.prelude.children;
  2347. if (node.pseudoSignature !== prev.pseudoSignature) {
  2348. return true;
  2349. }
  2350. allowMergeDown = !prevSelectors.some(function(selector) {
  2351. return selector.compareMarker in disallowDownMarkers;
  2352. });
  2353. // try prev ruleset if simpleselectors has no equal specifity and element selector
  2354. if (!allowMergeDown && !allowMergeUp) {
  2355. return true;
  2356. }
  2357. // try to join by selectors
  2358. if (allowMergeUp && utils$1.isEqualSelectors(prevSelectors, selectors)) {
  2359. prevBlock.children.appendList(block.children);
  2360. list.remove(item);
  2361. return true;
  2362. }
  2363. // try to join by properties
  2364. var diff = utils$1.compareDeclarations(block.children, prevBlock.children);
  2365. // console.log(diff.eq, diff.ne1, diff.ne2);
  2366. if (diff.eq.length) {
  2367. if (!diff.ne1.length && !diff.ne2.length) {
  2368. // equal blocks
  2369. if (allowMergeDown) {
  2370. utils$1.addSelectors(selectors, prevSelectors);
  2371. list.remove(prevItem);
  2372. }
  2373. return true;
  2374. } else if (!avoidRulesMerge) { /* probably we don't need to prevent those merges for @keyframes
  2375. TODO: need to be checked */
  2376. if (diff.ne1.length && !diff.ne2.length) {
  2377. // prevBlock is subset block
  2378. var selectorLength = calcSelectorLength(selectors);
  2379. var blockLength = calcDeclarationsLength(diff.eq); // declarations length
  2380. if (allowMergeUp && selectorLength < blockLength) {
  2381. utils$1.addSelectors(prevSelectors, selectors);
  2382. block.children = new List$4().fromArray(diff.ne1);
  2383. }
  2384. } else if (!diff.ne1.length && diff.ne2.length) {
  2385. // node is subset of prevBlock
  2386. var selectorLength = calcSelectorLength(prevSelectors);
  2387. var blockLength = calcDeclarationsLength(diff.eq); // declarations length
  2388. if (allowMergeDown && selectorLength < blockLength) {
  2389. utils$1.addSelectors(selectors, prevSelectors);
  2390. prevBlock.children = new List$4().fromArray(diff.ne2);
  2391. }
  2392. } else {
  2393. // diff.ne1.length && diff.ne2.length
  2394. // extract equal block
  2395. var newSelector = {
  2396. type: 'SelectorList',
  2397. loc: null,
  2398. children: utils$1.addSelectors(prevSelectors.copy(), selectors)
  2399. };
  2400. var newBlockLength = calcSelectorLength(newSelector.children) + 2; // selectors length + curly braces length
  2401. var blockLength = calcDeclarationsLength(diff.eq); // declarations length
  2402. // create new ruleset if declarations length greater than
  2403. // ruleset description overhead
  2404. if (blockLength >= newBlockLength) {
  2405. var newItem = list.createItem({
  2406. type: 'Rule',
  2407. loc: null,
  2408. prelude: newSelector,
  2409. block: {
  2410. type: 'Block',
  2411. loc: null,
  2412. children: new List$4().fromArray(diff.eq)
  2413. },
  2414. pseudoSignature: node.pseudoSignature
  2415. });
  2416. block.children = new List$4().fromArray(diff.ne1);
  2417. prevBlock.children = new List$4().fromArray(diff.ne2overrided);
  2418. if (allowMergeUp) {
  2419. list.insert(newItem, prevItem);
  2420. } else {
  2421. list.insert(newItem, item);
  2422. }
  2423. return true;
  2424. }
  2425. }
  2426. }
  2427. }
  2428. if (allowMergeUp) {
  2429. // TODO: disallow up merge only if any property interception only (i.e. diff.ne2overrided.length > 0);
  2430. // await property families to find property interception correctly
  2431. allowMergeUp = !prevSelectors.some(function(prevSelector) {
  2432. return selectors.some(function(selector) {
  2433. return selector.compareMarker === prevSelector.compareMarker;
  2434. });
  2435. });
  2436. }
  2437. prevSelectors.each(function(data) {
  2438. disallowDownMarkers[data.compareMarker] = true;
  2439. });
  2440. });
  2441. }
  2442. var _8RestructRuleset = function restructRule(ast) {
  2443. walk$a(ast, {
  2444. visit: 'Rule',
  2445. reverse: true,
  2446. enter: processRule$5
  2447. });
  2448. };
  2449. var restructure = function(ast, options) {
  2450. // prepare ast for restructing
  2451. var indexer = prepare(ast, options);
  2452. options.logger('prepare', ast);
  2453. _1MergeAtrule(ast, options);
  2454. options.logger('mergeAtrule', ast);
  2455. _2InitialMergeRuleset(ast);
  2456. options.logger('initialMergeRuleset', ast);
  2457. _3DisjoinRuleset(ast);
  2458. options.logger('disjoinRuleset', ast);
  2459. _4RestructShorthand(ast, indexer);
  2460. options.logger('restructShorthand', ast);
  2461. _6RestructBlock(ast);
  2462. options.logger('restructBlock', ast);
  2463. _7MergeRuleset(ast);
  2464. options.logger('mergeRuleset', ast);
  2465. _8RestructRuleset(ast);
  2466. options.logger('restructRuleset', ast);
  2467. };
  2468. var List$5 = csstree_min.List;
  2469. var clone = csstree_min.clone;
  2470. var walk$b = csstree_min.walk;
  2471. function readChunk(children, specialComments) {
  2472. var buffer = new List$5();
  2473. var nonSpaceTokenInBuffer = false;
  2474. var protectedComment;
  2475. children.nextUntil(children.head, function(node, item, list) {
  2476. if (node.type === 'Comment') {
  2477. if (!specialComments || node.value.charAt(0) !== '!') {
  2478. list.remove(item);
  2479. return;
  2480. }
  2481. if (nonSpaceTokenInBuffer || protectedComment) {
  2482. return true;
  2483. }
  2484. list.remove(item);
  2485. protectedComment = node;
  2486. return;
  2487. }
  2488. if (node.type !== 'WhiteSpace') {
  2489. nonSpaceTokenInBuffer = true;
  2490. }
  2491. buffer.insert(list.remove(item));
  2492. });
  2493. return {
  2494. comment: protectedComment,
  2495. stylesheet: {
  2496. type: 'StyleSheet',
  2497. loc: null,
  2498. children: buffer
  2499. }
  2500. };
  2501. }
  2502. function compressChunk(ast, firstAtrulesAllowed, num, options) {
  2503. options.logger('Compress block #' + num, null, true);
  2504. var seed = 1;
  2505. if (ast.type === 'StyleSheet') {
  2506. ast.firstAtrulesAllowed = firstAtrulesAllowed;
  2507. ast.id = seed++;
  2508. }
  2509. walk$b(ast, {
  2510. visit: 'Atrule',
  2511. enter: function markScopes(node) {
  2512. if (node.block !== null) {
  2513. node.block.id = seed++;
  2514. }
  2515. }
  2516. });
  2517. options.logger('init', ast);
  2518. // remove redundant
  2519. clean(ast, options);
  2520. options.logger('clean', ast);
  2521. // replace nodes for shortened forms
  2522. replace(ast);
  2523. options.logger('replace', ast);
  2524. // structure optimisations
  2525. if (options.restructuring) {
  2526. restructure(ast, options);
  2527. }
  2528. return ast;
  2529. }
  2530. function getCommentsOption(options) {
  2531. var comments = 'comments' in options ? options.comments : 'exclamation';
  2532. if (typeof comments === 'boolean') {
  2533. comments = comments ? 'exclamation' : false;
  2534. } else if (comments !== 'exclamation' && comments !== 'first-exclamation') {
  2535. comments = false;
  2536. }
  2537. return comments;
  2538. }
  2539. function getRestructureOption(options) {
  2540. if ('restructure' in options) {
  2541. return options.restructure;
  2542. }
  2543. return 'restructuring' in options ? options.restructuring : true;
  2544. }
  2545. function wrapBlock(block) {
  2546. return new List$5().appendData({
  2547. type: 'Rule',
  2548. loc: null,
  2549. prelude: {
  2550. type: 'SelectorList',
  2551. loc: null,
  2552. children: new List$5().appendData({
  2553. type: 'Selector',
  2554. loc: null,
  2555. children: new List$5().appendData({
  2556. type: 'TypeSelector',
  2557. loc: null,
  2558. name: 'x'
  2559. })
  2560. })
  2561. },
  2562. block: block
  2563. });
  2564. }
  2565. var compress = function compress(ast, options) {
  2566. ast = ast || { type: 'StyleSheet', loc: null, children: new List$5() };
  2567. options = options || {};
  2568. var compressOptions = {
  2569. logger: typeof options.logger === 'function' ? options.logger : function() {},
  2570. restructuring: getRestructureOption(options),
  2571. forceMediaMerge: Boolean(options.forceMediaMerge),
  2572. usage: options.usage ? usage.buildIndex(options.usage) : false
  2573. };
  2574. var specialComments = getCommentsOption(options);
  2575. var firstAtrulesAllowed = true;
  2576. var input;
  2577. var output = new List$5();
  2578. var chunk;
  2579. var chunkNum = 1;
  2580. var chunkChildren;
  2581. if (options.clone) {
  2582. ast = clone(ast);
  2583. }
  2584. if (ast.type === 'StyleSheet') {
  2585. input = ast.children;
  2586. ast.children = output;
  2587. } else {
  2588. input = wrapBlock(ast);
  2589. }
  2590. do {
  2591. chunk = readChunk(input, Boolean(specialComments));
  2592. compressChunk(chunk.stylesheet, firstAtrulesAllowed, chunkNum++, compressOptions);
  2593. chunkChildren = chunk.stylesheet.children;
  2594. if (chunk.comment) {
  2595. // add \n before comment if there is another content in output
  2596. if (!output.isEmpty()) {
  2597. output.insert(List$5.createItem({
  2598. type: 'Raw',
  2599. value: '\n'
  2600. }));
  2601. }
  2602. output.insert(List$5.createItem(chunk.comment));
  2603. // add \n after comment if chunk is not empty
  2604. if (!chunkChildren.isEmpty()) {
  2605. output.insert(List$5.createItem({
  2606. type: 'Raw',
  2607. value: '\n'
  2608. }));
  2609. }
  2610. }
  2611. if (firstAtrulesAllowed && !chunkChildren.isEmpty()) {
  2612. var lastRule = chunkChildren.last();
  2613. if (lastRule.type !== 'Atrule' ||
  2614. (lastRule.name !== 'import' && lastRule.name !== 'charset')) {
  2615. firstAtrulesAllowed = false;
  2616. }
  2617. }
  2618. if (specialComments !== 'exclamation') {
  2619. specialComments = false;
  2620. }
  2621. output.appendList(chunkChildren);
  2622. } while (!input.isEmpty());
  2623. return {
  2624. ast: ast
  2625. };
  2626. };
  2627. var version = "4.2.0";
  2628. var _package = {
  2629. version: version
  2630. };
  2631. var _package$1 = /*#__PURE__*/Object.freeze({
  2632. __proto__: null,
  2633. version: version,
  2634. 'default': _package
  2635. });
  2636. var require$$0 = getCjsExportFromNamespace(_package$1);
  2637. var parse = csstree_min.parse;
  2638. var generate$5 = csstree_min.generate;
  2639. function debugOutput(name, options, startTime, data) {
  2640. if (options.debug) {
  2641. console.error('## ' + name + ' done in %d ms\n', Date.now() - startTime);
  2642. }
  2643. return data;
  2644. }
  2645. function createDefaultLogger(level) {
  2646. var lastDebug;
  2647. return function logger(title, ast) {
  2648. var line = title;
  2649. if (ast) {
  2650. line = '[' + ((Date.now() - lastDebug) / 1000).toFixed(3) + 's] ' + line;
  2651. }
  2652. if (level > 1 && ast) {
  2653. var css = generate$5(ast);
  2654. // when level 2, limit css to 256 symbols
  2655. if (level === 2 && css.length > 256) {
  2656. css = css.substr(0, 256) + '...';
  2657. }
  2658. line += '\n ' + css + '\n';
  2659. }
  2660. console.error(line);
  2661. lastDebug = Date.now();
  2662. };
  2663. }
  2664. function copy(obj) {
  2665. var result = {};
  2666. for (var key in obj) {
  2667. result[key] = obj[key];
  2668. }
  2669. return result;
  2670. }
  2671. function buildCompressOptions(options) {
  2672. options = copy(options);
  2673. if (typeof options.logger !== 'function' && options.debug) {
  2674. options.logger = createDefaultLogger(options.debug);
  2675. }
  2676. return options;
  2677. }
  2678. function runHandler(ast, options, handlers) {
  2679. if (!Array.isArray(handlers)) {
  2680. handlers = [handlers];
  2681. }
  2682. handlers.forEach(function(fn) {
  2683. fn(ast, options);
  2684. });
  2685. }
  2686. function minify(context, source, options) {
  2687. options = options || {};
  2688. var filename = options.filename || '<unknown>';
  2689. var result;
  2690. // parse
  2691. var ast = debugOutput('parsing', options, Date.now(),
  2692. parse(source, {
  2693. context: context,
  2694. filename: filename,
  2695. positions: Boolean(options.sourceMap)
  2696. })
  2697. );
  2698. // before compress handlers
  2699. if (options.beforeCompress) {
  2700. debugOutput('beforeCompress', options, Date.now(),
  2701. runHandler(ast, options, options.beforeCompress)
  2702. );
  2703. }
  2704. // compress
  2705. var compressResult = debugOutput('compress', options, Date.now(),
  2706. compress(ast, buildCompressOptions(options))
  2707. );
  2708. // after compress handlers
  2709. if (options.afterCompress) {
  2710. debugOutput('afterCompress', options, Date.now(),
  2711. runHandler(compressResult, options, options.afterCompress)
  2712. );
  2713. }
  2714. // generate
  2715. if (options.sourceMap) {
  2716. result = debugOutput('generate(sourceMap: true)', options, Date.now(), (function() {
  2717. var tmp = generate$5(compressResult.ast, { sourceMap: true });
  2718. tmp.map._file = filename; // since other tools can relay on file in source map transform chain
  2719. tmp.map.setSourceContent(filename, source);
  2720. return tmp;
  2721. }()));
  2722. } else {
  2723. result = debugOutput('generate', options, Date.now(), {
  2724. css: generate$5(compressResult.ast),
  2725. map: null
  2726. });
  2727. }
  2728. return result;
  2729. }
  2730. function minifyStylesheet(source, options) {
  2731. return minify('stylesheet', source, options);
  2732. }
  2733. function minifyBlock(source, options) {
  2734. return minify('declarationList', source, options);
  2735. }
  2736. var lib = {
  2737. version: require$$0.version,
  2738. // main methods
  2739. minify: minifyStylesheet,
  2740. minifyBlock: minifyBlock,
  2741. // css syntax parser/walkers/generator/etc
  2742. syntax: Object.assign({
  2743. compress: compress
  2744. }, csstree_min)
  2745. };
  2746. var lib_1 = lib.version;
  2747. var lib_2 = lib.minify;
  2748. var lib_3 = lib.minifyBlock;
  2749. var lib_4 = lib.syntax;
  2750. exports.default = lib;
  2751. exports.minify = lib_2;
  2752. exports.minifyBlock = lib_3;
  2753. exports.syntax = lib_4;
  2754. exports.version = lib_1;
  2755. Object.defineProperty(exports, '__esModule', { value: true });
  2756. })));