This commit is contained in:
21
node_modules/@emmetio/css-parser/LICENSE
generated
vendored
Normal file
21
node_modules/@emmetio/css-parser/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Emmet.io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2
node_modules/@emmetio/css-parser/README.md
generated
vendored
Normal file
2
node_modules/@emmetio/css-parser/README.md
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# css-parser
|
||||
CSS/LESS/SCSS fast and minimalistic parser
|
||||
1620
node_modules/@emmetio/css-parser/dist/css-parser.cjs.js
generated
vendored
Normal file
1620
node_modules/@emmetio/css-parser/dist/css-parser.cjs.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1593
node_modules/@emmetio/css-parser/dist/css-parser.es.js
generated
vendored
Normal file
1593
node_modules/@emmetio/css-parser/dist/css-parser.es.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
887
node_modules/@emmetio/css-parser/dist/css-parser.js
generated
vendored
Normal file
887
node_modules/@emmetio/css-parser/dist/css-parser.js
generated
vendored
Normal file
@@ -0,0 +1,887 @@
|
||||
(function (exports) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* A streaming, character code-based string reader
|
||||
*/
|
||||
class StreamReader {
|
||||
constructor(string, start, end) {
|
||||
if (end == null && typeof string === 'string') {
|
||||
end = string.length;
|
||||
}
|
||||
|
||||
this.string = string;
|
||||
this.pos = this.start = start || 0;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if the stream is at the end of the file.
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
eof() {
|
||||
return this.pos >= this.end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stream instance which is limited to given `start` and `end`
|
||||
* range. E.g. its `eof()` method will look at `end` property, not actual
|
||||
* stream end
|
||||
* @param {Point} start
|
||||
* @param {Point} end
|
||||
* @return {StreamReader}
|
||||
*/
|
||||
limit(start, end) {
|
||||
return new this.constructor(this.string, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next character code in the stream without advancing it.
|
||||
* Will return NaN at the end of the file.
|
||||
* @returns {Number}
|
||||
*/
|
||||
peek() {
|
||||
return this.string.charCodeAt(this.pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next character in the stream and advances it.
|
||||
* Also returns <code>undefined</code> when no more characters are available.
|
||||
* @returns {Number}
|
||||
*/
|
||||
next() {
|
||||
if (this.pos < this.string.length) {
|
||||
return this.string.charCodeAt(this.pos++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `match` can be a character code or a function that takes a character code
|
||||
* and returns a boolean. If the next character in the stream 'matches'
|
||||
* the given argument, it is consumed and returned.
|
||||
* Otherwise, `false` is returned.
|
||||
* @param {Number|Function} match
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
eat(match) {
|
||||
const ch = this.peek();
|
||||
const ok = typeof match === 'function' ? match(ch) : ch === match;
|
||||
|
||||
if (ok) {
|
||||
this.next();
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeatedly calls <code>eat</code> with the given argument, until it
|
||||
* fails. Returns <code>true</code> if any characters were eaten.
|
||||
* @param {Object} match
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
eatWhile(match) {
|
||||
const start = this.pos;
|
||||
while (!this.eof() && this.eat(match)) {}
|
||||
return this.pos !== start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backs up the stream n characters. Backing it up further than the
|
||||
* start of the current token will cause things to break, so be careful.
|
||||
* @param {Number} n
|
||||
*/
|
||||
backUp(n) {
|
||||
this.pos -= (n || 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string between the start of the current token and the
|
||||
* current stream position.
|
||||
* @returns {String}
|
||||
*/
|
||||
current() {
|
||||
return this.substring(this.start, this.pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns substring for given range
|
||||
* @param {Number} start
|
||||
* @param {Number} [end]
|
||||
* @return {String}
|
||||
*/
|
||||
substring(start, end) {
|
||||
return this.string.slice(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates error object with current stream state
|
||||
* @param {String} message
|
||||
* @return {Error}
|
||||
*/
|
||||
error(message) {
|
||||
const err = new Error(`${message} at char ${this.pos + 1}`);
|
||||
err.originalMessage = message;
|
||||
err.pos = this.pos;
|
||||
err.string = this.string;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
class Container {
|
||||
constructor() {
|
||||
this.children = [];
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
get firstChild() {
|
||||
return this.children[0];
|
||||
}
|
||||
|
||||
get nextSibling() {
|
||||
const ix = this.index();
|
||||
return ix !== -1 ? this.parent.children[ix + 1] : null;
|
||||
}
|
||||
|
||||
get previousSibling() {
|
||||
const ix = this.index();
|
||||
return ix !== -1 ? this.parent.children[ix - 1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current element’s index in parent list of child nodes
|
||||
* @return {Number}
|
||||
*/
|
||||
index() {
|
||||
return this.parent ? this.parent.children.indexOf(this) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds given node as a child
|
||||
* @param {Node} node
|
||||
* @return {Node} Current node
|
||||
*/
|
||||
add(node) {
|
||||
if (node) {
|
||||
node.remove();
|
||||
this.children.push(node);
|
||||
node.parent = this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes current node from its parent
|
||||
* @return {Node} Current node
|
||||
*/
|
||||
remove() {
|
||||
if (this.parent) {
|
||||
const ix = this.index();
|
||||
if (ix !== -1) {
|
||||
this.parent.children.splice(ix, 1);
|
||||
this.parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class Stylesheet extends Container {
|
||||
constructor() {
|
||||
super();
|
||||
this.type = 'stylesheet';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns node’s start position in stream
|
||||
* @return {*}
|
||||
*/
|
||||
get start() {
|
||||
const node = this.firstChild;
|
||||
return node && node.start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns node’s end position in stream
|
||||
* @return {*}
|
||||
*/
|
||||
get end() {
|
||||
const node = this.children[this.children.length - 1];
|
||||
return node && node.end;
|
||||
}
|
||||
}
|
||||
|
||||
class Token {
|
||||
/**
|
||||
* @param {StreamReader} stream
|
||||
* @param {String} type Token type
|
||||
* @param {Object} [start] Tokens’ start position in `stream`
|
||||
* @param {Object} [end] Tokens’ end position in `stream`
|
||||
*/
|
||||
constructor(stream, type, start, end) {
|
||||
this.stream = stream;
|
||||
this.start = start != null ? start : stream.start;
|
||||
this.end = end != null ? end : stream.pos;
|
||||
this.type = type;
|
||||
|
||||
this._props = null;
|
||||
this._value = null;
|
||||
this._items = null;
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this._items ? this._items.length : 0;
|
||||
}
|
||||
|
||||
add(item) {
|
||||
if (item) {
|
||||
if (!this._items) {
|
||||
this._items = [item];
|
||||
} else {
|
||||
this._items.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
remove(item) {
|
||||
if (this._items) {
|
||||
const ix = this._items.indexOf(item);
|
||||
if (ix !== -1 ) {
|
||||
this._items.splice(ix, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
item(i) {
|
||||
return this._items && this._items[i];
|
||||
}
|
||||
|
||||
property(name, value) {
|
||||
if (typeof value !== 'undefined') {
|
||||
// set property value
|
||||
if (!this._props) {
|
||||
this._props = {};
|
||||
}
|
||||
|
||||
this._props[name] = value;
|
||||
}
|
||||
|
||||
return this._props && this._props[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns token textual representation
|
||||
* @return {String}
|
||||
*/
|
||||
toString() {
|
||||
return `${this.valueOf()} [${this.start}, ${this.end}]`;
|
||||
}
|
||||
|
||||
valueOf() {
|
||||
if (this._value === null) {
|
||||
this._value = this.stream.substring(this.start, this.end);
|
||||
}
|
||||
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes tokens that matches given criteria from start and end of given list
|
||||
* @param {Token[]} tokens
|
||||
* @param {Function} test
|
||||
* @return {Token[]}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Trims formatting tokens (whitespace and comments) from the beginning and end
|
||||
* of given token list
|
||||
* @param {Token[]} tokens
|
||||
* @return {Token[]}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Check if given token is a formatting one (whitespace or comment)
|
||||
* @param {Token} token
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Consumes string char-by-char from given stream
|
||||
* @param {StreamReader} stream
|
||||
* @param {String} string
|
||||
* @return {Boolean} Returns `true` if string was completely consumed
|
||||
*/
|
||||
function eatString(stream, string) {
|
||||
const start = stream.pos;
|
||||
|
||||
for (let i = 0, il = string.length; i < il; i++) {
|
||||
if (!stream.eat(string.charCodeAt(i))) {
|
||||
stream.pos = start;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function consumeWhile(stream, match) {
|
||||
const start = stream.pos;
|
||||
if (stream.eatWhile(match)) {
|
||||
stream.start = start;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns type of given token
|
||||
* @param {Token} token
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
|
||||
function last(arr) {
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
function createRule(stream, tokens, content) {
|
||||
if (!tokens.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let ix = 0;
|
||||
const name = tokens[ix++];
|
||||
|
||||
if (name.type === 'at-keyword') {
|
||||
let expression;
|
||||
if (ix < tokens.length) {
|
||||
expression = tokens[ix++];
|
||||
expression.type = 'expression';
|
||||
expression.end = last(tokens).end;
|
||||
} else {
|
||||
expression = new Token(stream, 'expression', name.end, name.end);
|
||||
}
|
||||
|
||||
return new AtRule(stream, name, expression, content);
|
||||
} else {
|
||||
name.end = last(tokens).end;
|
||||
}
|
||||
|
||||
return new Rule(stream, name, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents CSS rule
|
||||
* @type {Node}
|
||||
*/
|
||||
class Rule extends Container {
|
||||
/**
|
||||
* @param {StreamReader} stream
|
||||
* @param {Token} name Rule’s name token
|
||||
* @param {Token} content Rule’s content token
|
||||
*/
|
||||
constructor(stream, name, content) {
|
||||
super();
|
||||
this.type = 'rule';
|
||||
this.stream = stream;
|
||||
this.nameToken = name;
|
||||
this.contentToken = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns node name
|
||||
* @return {String}
|
||||
*/
|
||||
get name() {
|
||||
return valueOf(this.nameToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns node’s start position in stream
|
||||
* @return {*}
|
||||
*/
|
||||
get start() {
|
||||
return this.nameToken && this.nameToken.start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns node’s end position in stream
|
||||
* @return {*}
|
||||
*/
|
||||
get end() {
|
||||
const token = this.contentToken || this.nameToken;
|
||||
return token && token.end;
|
||||
}
|
||||
}
|
||||
|
||||
class AtRule extends Rule {
|
||||
constructor(stream, name, expression, content) {
|
||||
super(stream, name, content);
|
||||
this.type = 'at-rule';
|
||||
this.expressionToken = expression;
|
||||
}
|
||||
|
||||
get expressions() {
|
||||
return valueOf(this.expressionToken);
|
||||
}
|
||||
}
|
||||
|
||||
function valueOf(token) {
|
||||
return token && token.valueOf();
|
||||
}
|
||||
|
||||
function createProperty(stream, tokens, terminator) {
|
||||
// NB in LESS, fragmented properties without value like `.foo.bar;` must be
|
||||
// treated like mixin call
|
||||
if (!tokens.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let separator, value, ix = 0;
|
||||
const name = tokens[ix++];
|
||||
|
||||
if (ix < tokens.length) {
|
||||
value = tokens[ix++];
|
||||
value.type = 'value';
|
||||
value.end = last(tokens).end;
|
||||
}
|
||||
|
||||
if (name && value) {
|
||||
separator = new Token(stream, 'separator', name.end, value.start);
|
||||
}
|
||||
|
||||
return new Property(
|
||||
stream,
|
||||
name,
|
||||
value,
|
||||
separator,
|
||||
terminator
|
||||
);
|
||||
}
|
||||
|
||||
class Property {
|
||||
constructor(stream, name, value, separator, terminator) {
|
||||
this.type = 'property';
|
||||
this.stream = stream;
|
||||
this.nameToken = name;
|
||||
this.valueToken = value;
|
||||
|
||||
this.separatorToken = separator;
|
||||
this.terminatorToken = terminator;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return valueOf$1(this.nameToken);
|
||||
}
|
||||
|
||||
get value() {
|
||||
return valueOf$1(this.valueToken);
|
||||
}
|
||||
|
||||
get separator() {
|
||||
return valueOf$1(this.separatorToken);
|
||||
}
|
||||
|
||||
get terminator() {
|
||||
return valueOf$1(this.terminatorToken);
|
||||
}
|
||||
|
||||
get start() {
|
||||
const token = this.nameToken || this.separatorToken || this.valueToken
|
||||
|| this.terminatorToken;
|
||||
return token && token.start;
|
||||
}
|
||||
|
||||
get end() {
|
||||
const token = this.terminatorToken || this.valueToken
|
||||
|| this.separatorToken || this.nameToken;
|
||||
return token && token.end;
|
||||
}
|
||||
}
|
||||
|
||||
function valueOf$1(token) {
|
||||
return token && token.valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods for consuming quoted values
|
||||
*/
|
||||
|
||||
const SINGLE_QUOTE = 39; // '
|
||||
const DOUBLE_QUOTE = 34; // "
|
||||
|
||||
function isQuote(code) {
|
||||
return code === SINGLE_QUOTE || code === DOUBLE_QUOTE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given code is a number
|
||||
* @param {Number} code
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isNumber(code) {
|
||||
return code > 47 && code < 58;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given character code is alpha code (letter through A to Z)
|
||||
* @param {Number} code
|
||||
* @param {Number} [from]
|
||||
* @param {Number} [to]
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isAlpha(code, from, to) {
|
||||
from = from || 65; // A
|
||||
to = to || 90; // Z
|
||||
code &= ~32; // quick hack to convert any char code to uppercase char code
|
||||
|
||||
return code >= from && code <= to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given character code is alpha-numeric (letter through A to Z or number)
|
||||
* @param {Number} code
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isWhiteSpace(code) {
|
||||
return code === 32 /* space */
|
||||
|| code === 9 /* tab */
|
||||
|| code === 160; /* non-breaking space */
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given character code is a space
|
||||
* @param {Number} code
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isSpace(code) {
|
||||
return isWhiteSpace(code)
|
||||
|| code === 10 /* LF */
|
||||
|| code === 13; /* CR */
|
||||
}
|
||||
|
||||
const HYPHEN = 45;
|
||||
const UNDERSCORE = 95;
|
||||
|
||||
function ident(stream) {
|
||||
return eatIdent(stream) && new Token(stream, 'ident');
|
||||
}
|
||||
|
||||
function eatIdent(stream) {
|
||||
const start = stream.pos;
|
||||
|
||||
stream.eat(HYPHEN);
|
||||
if (stream.eat(isIdentStart)) {
|
||||
stream.eatWhile(isIdent);
|
||||
stream.start = start;
|
||||
return true;
|
||||
}
|
||||
|
||||
stream.pos = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isIdentStart(code) {
|
||||
return code === UNDERSCORE || code === HYPHEN || isAlpha(code) || code >= 128;
|
||||
}
|
||||
|
||||
function isIdent(code) {
|
||||
return isNumber(code) || isIdentStart(code);
|
||||
}
|
||||
|
||||
function prefixed(stream, tokenType, prefix, body, allowEmptyBody) {
|
||||
const start = stream.pos;
|
||||
|
||||
if (stream.eat(prefix)) {
|
||||
const bodyToken = body(stream, start);
|
||||
if (bodyToken || allowEmptyBody) {
|
||||
stream.start = start;
|
||||
return new Token(stream, tokenType, start).add(bodyToken);
|
||||
}
|
||||
}
|
||||
|
||||
stream.pos = start;
|
||||
}
|
||||
|
||||
const AT = 64; // @
|
||||
|
||||
/**
|
||||
* Consumes at-keyword from given stream
|
||||
*/
|
||||
function atKeyword(stream) {
|
||||
return prefixed(stream, 'at-keyword', AT, ident);
|
||||
}
|
||||
|
||||
function eatString$1(stream, asToken) {
|
||||
let ch = stream.peek(), pos;
|
||||
|
||||
if (isQuote(ch)) {
|
||||
stream.start = stream.pos;
|
||||
stream.next();
|
||||
const quote = ch;
|
||||
const valueStart = stream.pos;
|
||||
|
||||
while (!stream.eof()) {
|
||||
pos = stream.pos;
|
||||
if (stream.eat(quote) || stream.eat(isNewline)) {
|
||||
// found end of string or newline without preceding '\',
|
||||
// which is not allowed (don’t throw error, for now)
|
||||
break;
|
||||
} else if (stream.eat(92 /* \ */)) {
|
||||
// backslash allows newline in string
|
||||
stream.eat(isNewline);
|
||||
}
|
||||
|
||||
stream.next();
|
||||
}
|
||||
|
||||
// Either reached EOF or explicitly stopped at string end
|
||||
// NB use extra `asToken` param to return boolean instead of token to reduce
|
||||
// memory allocations and improve performance
|
||||
if (asToken) {
|
||||
const token = new Token(stream, 'string');
|
||||
token.add(new Token(stream, 'unquoted', valueStart, pos));
|
||||
token.property('quote', quote);
|
||||
return token;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isNewline(code) {
|
||||
return code === 10 /* LF */ || code === 13 /* CR */;
|
||||
}
|
||||
|
||||
const ASTERISK = 42;
|
||||
const SLASH = 47;
|
||||
|
||||
/**
|
||||
* Consumes comment from given stream: either multi-line or single-line
|
||||
* @param {StreamReader} stream
|
||||
* @return {CommentToken}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
function eatComment(stream) {
|
||||
return eatSingleLineComment(stream) || eatMultiLineComment(stream);
|
||||
}
|
||||
|
||||
function eatSingleLineComment(stream) {
|
||||
const start = stream.pos;
|
||||
|
||||
if (stream.eat(SLASH) && stream.eat(SLASH)) {
|
||||
// single-line comment, consume till the end of line
|
||||
stream.start = start;
|
||||
while (!stream.eof()) {
|
||||
if (isLineBreak(stream.next())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
stream.pos = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
function eatMultiLineComment(stream) {
|
||||
const start = stream.pos;
|
||||
|
||||
if (stream.eat(SLASH) && stream.eat(ASTERISK)) {
|
||||
while (!stream.eof()) {
|
||||
if (stream.next() === ASTERISK && stream.eat(SLASH)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stream.start = start;
|
||||
return true;
|
||||
}
|
||||
|
||||
stream.pos = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLineBreak(code) {
|
||||
return code === 10 /* LF */ || code === 13 /* CR */;
|
||||
}
|
||||
|
||||
function eatWhitespace(stream) {
|
||||
return consumeWhile(stream, isSpace);
|
||||
}
|
||||
|
||||
function eatUnquoted(stream) {
|
||||
return consumeWhile(stream, isUnquoted);
|
||||
}
|
||||
|
||||
function isUnquoted(code) {
|
||||
return !isNaN(code) && !isQuote(code) && !isSpace(code)
|
||||
&& code !== 40 /* ( */ && code !== 41 /* ) */ && code !== 92 /* \ */
|
||||
&& !isNonPrintable(code);
|
||||
}
|
||||
|
||||
function isNonPrintable(code) {
|
||||
return (code >= 0 && code <= 8) || code === 11
|
||||
|| (code >= 14 && code <= 31) || code === 127;
|
||||
}
|
||||
|
||||
function eatUrl(stream) {
|
||||
const start = stream.pos;
|
||||
|
||||
if (eatString(stream, 'url(')) {
|
||||
eatWhitespace(stream);
|
||||
eatString$1(stream) || eatUnquoted(stream);
|
||||
eatWhitespace(stream);
|
||||
stream.eat(41); // )
|
||||
stream.start = start;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
stream.pos = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
const LBRACE = 40; // (
|
||||
const RBRACE = 41; // )
|
||||
const PROP_DELIMITER = 58; // :
|
||||
const PROP_TERMINATOR = 59; // ;
|
||||
const RULE_START = 123; // {
|
||||
const RULE_END = 125; // }
|
||||
|
||||
function parseStylesheet(source) {
|
||||
const stream = typeof source === 'string' ? new StreamReader(source) : source;
|
||||
const root = new Stylesheet();
|
||||
let ctx = root, child, accum, token;
|
||||
let tokens = [];
|
||||
const flush = () => {
|
||||
if (accum) {
|
||||
tokens.push(accum);
|
||||
accum = null;
|
||||
}
|
||||
};
|
||||
|
||||
while (!stream.eof()) {
|
||||
if (eatWhitespace(stream) || eatComment(stream)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stream.start = stream.pos;
|
||||
|
||||
if (stream.eatWhile(PROP_DELIMITER)) {
|
||||
// Property delimiter can be either a real property delimiter or a
|
||||
// part of pseudo-selector.
|
||||
if (!tokens.length) {
|
||||
if (accum) {
|
||||
// No consumed tokens yet but pending token: most likely it’s
|
||||
// a CSS property
|
||||
flush();
|
||||
} else {
|
||||
// No consumend or accumulated token, seems like a start of
|
||||
// pseudo-selector, e.g. `::slotted`
|
||||
accum = new Token(stream, 'preparse');
|
||||
}
|
||||
}
|
||||
// Skip delimiter if there are already consumend tokens: most likely
|
||||
// it’s a part of pseudo-selector
|
||||
} else if (stream.eat(RULE_END)) {
|
||||
flush();
|
||||
|
||||
// Finalize context section
|
||||
ctx.add(createProperty(stream, tokens));
|
||||
|
||||
if (ctx.type !== 'stylesheet') {
|
||||
// In case of invalid stylesheet with redundant `}`,
|
||||
// don’t modify root section.
|
||||
ctx.contentToken.end = stream.pos;
|
||||
ctx = ctx.parent;
|
||||
}
|
||||
|
||||
tokens.length = 0;
|
||||
} else if (stream.eat(PROP_TERMINATOR)) {
|
||||
flush();
|
||||
ctx.add(createProperty(stream, tokens, new Token(stream, 'termintator')));
|
||||
tokens.length = 0;
|
||||
} else if (stream.eat(RULE_START)) {
|
||||
flush();
|
||||
child = createRule(stream, tokens, new Token(stream, 'body'));
|
||||
ctx.add(child);
|
||||
ctx = child;
|
||||
tokens.length = 0;
|
||||
} else if (token = atKeyword(stream)) {
|
||||
// Explictly consume @-tokens since it defines how rule or property
|
||||
// should be pre-parsed
|
||||
flush();
|
||||
tokens.push(token);
|
||||
} else if (eatUrl(stream) || eatBraces(stream) || eatString$1(stream) || stream.next()) {
|
||||
// NB explicitly consume `url()` token since it may contain
|
||||
// an unquoted url like `http://example.com` which interferes
|
||||
// with single-line comment
|
||||
accum = accum || new Token(stream, 'preparse');
|
||||
accum.end = stream.pos;
|
||||
} else {
|
||||
throw new Error(`Unexpected end-of-stream at ${stream.pos}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (accum) {
|
||||
tokens.push(accum);
|
||||
}
|
||||
|
||||
// Finalize all the rest properties
|
||||
ctx.add(createProperty(stream, tokens));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes content inside round braces. Mostly used to skip `;` token inside
|
||||
* expressions since in LESS it is also used to separate function arguments
|
||||
* @param {StringReader} stream
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function eatBraces(stream) {
|
||||
if (stream.eat(LBRACE)) {
|
||||
let stack = 1;
|
||||
|
||||
while (!stream.eof()) {
|
||||
if (stream.eat(RBRACE)) {
|
||||
stack--;
|
||||
if (!stack) {
|
||||
break;
|
||||
}
|
||||
} else if (stream.eat(LBRACE)) {
|
||||
stack++;
|
||||
} else {
|
||||
eatUrl(stream) || eatString$1(stream) || eatComment(stream) || stream.next();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
exports['default'] = parseStylesheet;
|
||||
|
||||
}((this.cssParser = this.cssParser || {})));
|
||||
1224
node_modules/@emmetio/css-parser/dist/html-matcher.cjs.js
generated
vendored
Normal file
1224
node_modules/@emmetio/css-parser/dist/html-matcher.cjs.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1214
node_modules/@emmetio/css-parser/dist/html-matcher.es.js
generated
vendored
Normal file
1214
node_modules/@emmetio/css-parser/dist/html-matcher.es.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
node_modules/@emmetio/css-parser/package.json
generated
vendored
Normal file
36
node_modules/@emmetio/css-parser/package.json
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@emmetio/css-parser",
|
||||
"version": "0.4.0",
|
||||
"description": "CSS/LESS/SCSS fast and minimalistic parser",
|
||||
"main": "./dist/css-parser.cjs.js",
|
||||
"module": "./dist/css-parser.es.js",
|
||||
"dependencies": {
|
||||
"@emmetio/stream-reader": "^2.2.0",
|
||||
"@emmetio/stream-reader-utils": "^0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
|
||||
"babel-register": "^6.24.1",
|
||||
"mocha": "^3.2.0",
|
||||
"rollup": "^0.41.6",
|
||||
"rollup-plugin-node-resolve": "^3.0.0",
|
||||
"rollup-watch": "^3.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"build": "rollup -c",
|
||||
"watch": "rollup -wc",
|
||||
"prepublish": "npm run test && npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/emmetio/css-parser.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Sergey Chikuyonok <serge.che@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/emmetio/css-parser/issues"
|
||||
},
|
||||
"homepage": "https://github.com/emmetio/css-parser#readme"
|
||||
}
|
||||
Reference in New Issue
Block a user