| Index: appengine/config_service/ui/bower_components/shadycss/src/css-parse.js
|
| diff --git a/appengine/config_service/ui/bower_components/shadycss/src/css-parse.js b/appengine/config_service/ui/bower_components/shadycss/src/css-parse.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8a8fb1cd9eab9c868e521ba5f8b97f176eb52a00
|
| --- /dev/null
|
| +++ b/appengine/config_service/ui/bower_components/shadycss/src/css-parse.js
|
| @@ -0,0 +1,264 @@
|
| +/**
|
| +@license
|
| +Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
| +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
| +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
| +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
| +Code distributed by Google as part of the polymer project is also
|
| +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
| +*/
|
| +
|
| +/*
|
| +Extremely simple css parser. Intended to be not more than what we need
|
| +and definitely not necessarily correct =).
|
| +*/
|
| +
|
| +'use strict';
|
| +
|
| +/** @unrestricted */
|
| +class StyleNode {
|
| + constructor() {
|
| + /** @type {number} */
|
| + this['start'] = 0;
|
| + /** @type {number} */
|
| + this['end'] = 0;
|
| + /** @type {StyleNode} */
|
| + this['previous'] = null;
|
| + /** @type {StyleNode} */
|
| + this['parent'] = null;
|
| + /** @type {Array<StyleNode>} */
|
| + this['rules'] = null;
|
| + /** @type {string} */
|
| + this['parsedCssText'] = '';
|
| + /** @type {string} */
|
| + this['cssText'] = '';
|
| + /** @type {boolean} */
|
| + this['atRule'] = false;
|
| + /** @type {number} */
|
| + this['type'] = 0;
|
| + /** @type {string} */
|
| + this['keyframesName'] = '';
|
| + /** @type {string} */
|
| + this['selector'] = '';
|
| + /** @type {string} */
|
| + this['parsedSelector'] = '';
|
| + }
|
| +}
|
| +
|
| +export {StyleNode}
|
| +
|
| +// given a string of css, return a simple rule tree
|
| +/**
|
| + * @param {string} text
|
| + * @return {StyleNode}
|
| + */
|
| +export function parse(text) {
|
| + text = clean(text);
|
| + return parseCss(lex(text), text);
|
| +}
|
| +
|
| +// remove stuff we don't care about that may hinder parsing
|
| +/**
|
| + * @param {string} cssText
|
| + * @return {string}
|
| + */
|
| +function clean(cssText) {
|
| + return cssText.replace(RX.comments, '').replace(RX.port, '');
|
| +}
|
| +
|
| +// super simple {...} lexer that returns a node tree
|
| +/**
|
| + * @param {string} text
|
| + * @return {StyleNode}
|
| + */
|
| +function lex(text) {
|
| + let root = new StyleNode();
|
| + root['start'] = 0;
|
| + root['end'] = text.length
|
| + let n = root;
|
| + for (let i = 0, l = text.length; i < l; i++) {
|
| + if (text[i] === OPEN_BRACE) {
|
| + if (!n['rules']) {
|
| + n['rules'] = [];
|
| + }
|
| + let p = n;
|
| + let previous = p['rules'][p['rules'].length - 1] || null;
|
| + n = new StyleNode();
|
| + n['start'] = i + 1;
|
| + n['parent'] = p;
|
| + n['previous'] = previous;
|
| + p['rules'].push(n);
|
| + } else if (text[i] === CLOSE_BRACE) {
|
| + n['end'] = i + 1;
|
| + n = n['parent'] || root;
|
| + }
|
| + }
|
| + return root;
|
| +}
|
| +
|
| +// add selectors/cssText to node tree
|
| +/**
|
| + * @param {StyleNode} node
|
| + * @param {string} text
|
| + * @return {StyleNode}
|
| + */
|
| +function parseCss(node, text) {
|
| + let t = text.substring(node['start'], node['end'] - 1);
|
| + node['parsedCssText'] = node['cssText'] = t.trim();
|
| + if (node['parent']) {
|
| + let ss = node['previous'] ? node['previous']['end'] : node['parent']['start'];
|
| + t = text.substring(ss, node['start'] - 1);
|
| + t = _expandUnicodeEscapes(t);
|
| + t = t.replace(RX.multipleSpaces, ' ');
|
| + // TODO(sorvell): ad hoc; make selector include only after last ;
|
| + // helps with mixin syntax
|
| + t = t.substring(t.lastIndexOf(';') + 1);
|
| + let s = node['parsedSelector'] = node['selector'] = t.trim();
|
| + node['atRule'] = (s.indexOf(AT_START) === 0);
|
| + // note, support a subset of rule types...
|
| + if (node['atRule']) {
|
| + if (s.indexOf(MEDIA_START) === 0) {
|
| + node['type'] = types.MEDIA_RULE;
|
| + } else if (s.match(RX.keyframesRule)) {
|
| + node['type'] = types.KEYFRAMES_RULE;
|
| + node['keyframesName'] =
|
| + node['selector'].split(RX.multipleSpaces).pop();
|
| + }
|
| + } else {
|
| + if (s.indexOf(VAR_START) === 0) {
|
| + node['type'] = types.MIXIN_RULE;
|
| + } else {
|
| + node['type'] = types.STYLE_RULE;
|
| + }
|
| + }
|
| + }
|
| + let r$ = node['rules'];
|
| + if (r$) {
|
| + for (let i = 0, l = r$.length, r;
|
| + (i < l) && (r = r$[i]); i++) {
|
| + parseCss(r, text);
|
| + }
|
| + }
|
| + return node;
|
| +}
|
| +
|
| +/**
|
| + * conversion of sort unicode escapes with spaces like `\33 ` (and longer) into
|
| + * expanded form that doesn't require trailing space `\000033`
|
| + * @param {string} s
|
| + * @return {string}
|
| + */
|
| +function _expandUnicodeEscapes(s) {
|
| + return s.replace(/\\([0-9a-f]{1,6})\s/gi, function() {
|
| + let code = arguments[1],
|
| + repeat = 6 - code.length;
|
| + while (repeat--) {
|
| + code = '0' + code;
|
| + }
|
| + return '\\' + code;
|
| + });
|
| +}
|
| +
|
| +/**
|
| + * stringify parsed css.
|
| + * @param {StyleNode} node
|
| + * @param {boolean=} preserveProperties
|
| + * @param {string=} text
|
| + * @return {string}
|
| + */
|
| +export function stringify(node, preserveProperties, text = '') {
|
| + // calc rule cssText
|
| + let cssText = '';
|
| + if (node['cssText'] || node['rules']) {
|
| + let r$ = node['rules'];
|
| + if (r$ && !_hasMixinRules(r$)) {
|
| + for (let i = 0, l = r$.length, r;
|
| + (i < l) && (r = r$[i]); i++) {
|
| + cssText = stringify(r, preserveProperties, cssText);
|
| + }
|
| + } else {
|
| + cssText = preserveProperties ? node['cssText'] :
|
| + removeCustomProps(node['cssText']);
|
| + cssText = cssText.trim();
|
| + if (cssText) {
|
| + cssText = ' ' + cssText + '\n';
|
| + }
|
| + }
|
| + }
|
| + // emit rule if there is cssText
|
| + if (cssText) {
|
| + if (node['selector']) {
|
| + text += node['selector'] + ' ' + OPEN_BRACE + '\n';
|
| + }
|
| + text += cssText;
|
| + if (node['selector']) {
|
| + text += CLOSE_BRACE + '\n\n';
|
| + }
|
| + }
|
| + return text;
|
| +}
|
| +
|
| +/**
|
| + * @param {Array<StyleNode>} rules
|
| + * @return {boolean}
|
| + */
|
| +function _hasMixinRules(rules) {
|
| + let r = rules[0];
|
| + return Boolean(r) && Boolean(r['selector']) && r['selector'].indexOf(VAR_START) === 0;
|
| +}
|
| +
|
| +/**
|
| + * @param {string} cssText
|
| + * @return {string}
|
| + */
|
| +function removeCustomProps(cssText) {
|
| + cssText = removeCustomPropAssignment(cssText);
|
| + return removeCustomPropApply(cssText);
|
| +}
|
| +
|
| +/**
|
| + * @param {string} cssText
|
| + * @return {string}
|
| + */
|
| +export function removeCustomPropAssignment(cssText) {
|
| + return cssText
|
| + .replace(RX.customProp, '')
|
| + .replace(RX.mixinProp, '');
|
| +}
|
| +
|
| +/**
|
| + * @param {string} cssText
|
| + * @return {string}
|
| + */
|
| +function removeCustomPropApply(cssText) {
|
| + return cssText
|
| + .replace(RX.mixinApply, '')
|
| + .replace(RX.varApply, '');
|
| +}
|
| +
|
| +/** @enum {number} */
|
| +export const types = {
|
| + STYLE_RULE: 1,
|
| + KEYFRAMES_RULE: 7,
|
| + MEDIA_RULE: 4,
|
| + MIXIN_RULE: 1000
|
| +}
|
| +
|
| +const OPEN_BRACE = '{';
|
| +const CLOSE_BRACE = '}';
|
| +
|
| +// helper regexp's
|
| +const RX = {
|
| + comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
|
| + port: /@import[^;]*;/gim,
|
| + customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
|
| + mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
|
| + mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,
|
| + varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
|
| + keyframesRule: /^@[^\s]*keyframes/,
|
| + multipleSpaces: /\s+/g
|
| +}
|
| +
|
| +const VAR_START = '--';
|
| +const MEDIA_START = '@media';
|
| +const AT_START = '@';
|
|
|