Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
"use strict";

// const { get } = require('lodash')
// const log = require('fliplog')
const _require = require("./modules/chain-able"),
      toUniverseView = _require.toUniverseView,
      dot = _require.dot;

const set = dot.set;
/* eslint-disable brace-style */
// https://mdn.mozillademos.org/files/3665/css%20syntax%20-%20declaration.png

let Selector = class Selector {} // & ~ + * [=""] : ,
//             lowercase-or-numbers
;
Selector.className = /^([a-z][a-z0-9]*)(-[a-z0-9]+)*$/; // same as above, but starts with `.` ends with `{`

Selector.match = /^.([a-z][a-z0-9]*)(-[a-z0-9]+)*/;

const isStarOrDoubleSlash = line => line.startsWith('/*') || line.startsWith('//'); // const isStarOrDoubleSlash = char => char === '*' || char === '//'
// const isComment = line => line.charAt(0) === '/' && isStarOrDoubleSlash(line.charAt(1))


const isComment = line => line.startsWith('/') && isStarOrDoubleSlash(line);

const not = fn => x => !fn(x);

const isNotComment = not(isComment);

const trim = x => x.trim();

const isNotEmpty = line => line !== '';

const removeFirst = current => {
  current = current.split('');
  current.shift();
  current = current.join('');
  return current;
};

const removeLast = (current, num = 1) => {
  current = current.split('');

  while (num > 0) {
    num -= 1;
    current.pop();
  }

  current = current.join('');
  return current;
};

const reverse = x => x.split('').reverse().join('');

const removeIndentWhile = str => {
  let current = str.replace(/\t\r\n/gmi, '');

  while (current.charAt(0) === ' ') {
    current = removeFirst(current);
  }

  return current;
};

const removeIndents = str => {
  str = removeIndentWhile(str);
  str = reverse(str);
  str = removeIndentWhile(str);
  str = reverse(str);
  return str;
};

const isSelector = line => Selector.match.test(line); // isSelector(line) &&


const isMultiLineSelector = line => line.endsWith(','); // isSelector(line) &&


const isSelectorEnd = line => line.endsWith('{');

const isRuleEnd = line => line.endsWith('}');

function toPath(line) {
  line = line // esc
  // .replace(/\./gmi, '\\.')
  // .split(' ').join('.')
  .split('.').join('\\.') // .split('\\.\\.').join('\\.')
  // .map(l => l === '.')
  // ---
  // .replace(/\.\s/gim, '')
  // .replace(/\./gim, ' ')
  // .replace(/\s+/gim, '.')
  // .replace(/ /gmi, '')
  // .replace(/(\s|\t|\n|\r)+/gmi, '')
  .trim(); // return removeLast(line)

  if (line.endsWith('\\.')) {
    return removeLast(line, 2);
  } // replace first dot if it exists


  return line.charAt(0) === '.' ? line.replace('.', '') : line;
}

let Declaration = class Declaration {
  constructor(property, value) {
    this.property = property;
    this.value = value;
  }

};
let Parser = class Parser {
  constructor(css) {
    this.css = css; // this.level = 0

    this.store = new Map();
    this.obj = {};
    this.selectorPath = [];
    this.selectorGroupStack = false; // this.history = []
    // this.stack = []
    // this.path = []

    this.mapLine = this.mapLine.bind(this);
  }

  get selector() {
    return this.selectorPath.join(' ');
  }

  get(selector) {
    return this.store.get(selector);
  }

  set(selector) {
    if (this.store.has(selector)) {
      return;
    }

    const line = {
      selectors: [selector],
      rules: []
    };
    this.store.set(selector, line); // this.selectorPath.push(selector)
  }

  last() {
    return this.selectorPath[this.selectorPath.length - 1];
  }

  lastWasMultiLineSelector() {
    let last = this.last();
    if (!last) return false;
    return isMultiLineSelector(last);
  }

  add(line) {
    line = line.replace(/\&/gmi, '').trim();
    this.selectorPath.push(line);
    this.set(this.selector);
    const path = toPath(this.selector);
    set(this.obj, path, this.get(this.selector).rules);
    toUniverseView(this.obj);
  }

  pop(line) {
    this.selectorPath.pop();
  }

  mapLine(line) {
    if (isMultiLineSelector(line)) {
      line = removeLast(line);

      if (this.selectorGroupStack) {
        this.selectorGroupStack.push(line);
      } else {
        this.selectorGroupStack = [line];
      }
    }

    if (isSelectorEnd(line)) {
      line = removeLast(line); // line = line.trim()
      // this is the annoying part...

      if (this.selectorGroupStack) {
        const selector = this.selector;
        const selectorGroupStack = this.selectorGroupStack.concat([line]);
        this.selectorGroupStack = false;
        selectorGroupStack.forEach((nestedSelector, index) => {
          const isLast = index === selectorGroupStack.length - 1;
          let nested = nestedSelector;

          if (isLast) {
            nested = selector + nestedSelector;
            nested += ',';
          } else {
            nested = selector + nestedSelector;
          }

          this.add(nested);
        });
      } else {
        this.add(line);
      }
    } else if (isRuleEnd(line)) {
      this.pop();
    } else {
      // console.log(this.selector, line)
      const group = this.get(this.selector); // console.log(group, this.selector)

      group.rules.push(line);
    } // console.log(this.selectorPath)

  }

  parse(css) {
    const mapped = css.split('\n').map(removeIndents).filter(isNotComment) // .filter(x => isComment(x))
    .filter(isNotEmpty).map(this.mapLine);
    Array.from(this.store.keys()).forEach(name => {
      console.log('\n');
      const value = this.get(name); // log.fmtobj({ [name]: value.rules }).echo()
      // log.bold(name).echo()
      // log.blue('selectors').data(value.selectors).echo()
      // log.yellow('rules').data(value.rules).echo()
      // console.log({ [name]: value })

      console.log('\n');
    }); // log.fmtobj(this.obj.toFlat(false)).echo()
    // log.quick((this.obj))
    // log.quick(toUniverseView(this.obj, true))
    // console.log(this.selector)

    return css;
  }

};

function parse(css) {
  return new Parser(css).parse(css);
}

module.exports = parse;