🎉 initiate project *astro_rewrite*
This commit is contained in:
parent
ffd4d5e86c
commit
2ba37bfbe3
8658 changed files with 2268794 additions and 2538 deletions
21
node_modules/@emmetio/css-abbreviation/LICENSE
generated
vendored
Normal file
21
node_modules/@emmetio/css-abbreviation/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Sergey Chikuyonok <serge.che@gmail.com>
|
||||
|
||||
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.
|
||||
39
node_modules/@emmetio/css-abbreviation/README.md
generated
vendored
Normal file
39
node_modules/@emmetio/css-abbreviation/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Emmet stylesheet abbreviation parser
|
||||
|
||||
Parses given Emmet *stylesheet* abbreviation into AST. Parsing is performed in two steps: first it tokenizes given abbreviation (useful for syntax highlighting in editors) and then tokens are analyzed and converted into AST nodes as plain, JSON-serializable objects.
|
||||
|
||||
Unlike in [markup abbreviations](/packages/abbreviation), elements in stylesheet abbreviations cannot be nested and contain attributes, but allow embedded values in element names.
|
||||
|
||||
## Usage
|
||||
|
||||
You can install it via npm:
|
||||
|
||||
```bash
|
||||
npm install @emmetio/css-abbreviation
|
||||
```
|
||||
|
||||
Then add it into your project:
|
||||
|
||||
```js
|
||||
import parse from '@emmetio/css-abbreviation';
|
||||
|
||||
const props = parse('p10+poa');
|
||||
/* [{
|
||||
name: 'p',
|
||||
value: [{ type: 'CSSValue', value: [...] }],
|
||||
important: false
|
||||
}, {
|
||||
name: 'poa',
|
||||
value: [],
|
||||
important: false
|
||||
}] */
|
||||
```
|
||||
The returned result is an array of `CSSProperty` items: a node with name and values.
|
||||
|
||||
## Abbreviation syntax
|
||||
|
||||
Emmet stylesheet abbreviation element may start with name and followed by values, optionally chained with `-` delimiter. In most cases, actual CSS properties doesn’t have numbers in their names (or at least they are not used in abbreviation shortcuts) so a number right after alpha characters is considered as *embedded value*, as well as colors starting with `#` character: `p10`, `bg#fc0` etc. If implicit name/value boundary can’t be identified, you should use `-` as value separator: `m-a`, `p10-20` etc.
|
||||
|
||||
### Operators
|
||||
|
||||
Since CSS properties can’t be nested, the only available operator is `+`.
|
||||
687
node_modules/@emmetio/css-abbreviation/dist/index.cjs
generated
vendored
Normal file
687
node_modules/@emmetio/css-abbreviation/dist/index.cjs
generated
vendored
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var Scanner = require('@emmetio/scanner');
|
||||
|
||||
exports.OperatorType = void 0;
|
||||
(function (OperatorType) {
|
||||
OperatorType["Sibling"] = "+";
|
||||
OperatorType["Important"] = "!";
|
||||
OperatorType["ArgumentDelimiter"] = ",";
|
||||
OperatorType["ValueDelimiter"] = "-";
|
||||
OperatorType["PropertyDelimiter"] = ":";
|
||||
})(exports.OperatorType || (exports.OperatorType = {}));
|
||||
|
||||
var Chars;
|
||||
(function (Chars) {
|
||||
/** `#` character */
|
||||
Chars[Chars["Hash"] = 35] = "Hash";
|
||||
/** `$` character */
|
||||
Chars[Chars["Dollar"] = 36] = "Dollar";
|
||||
/** `-` character */
|
||||
Chars[Chars["Dash"] = 45] = "Dash";
|
||||
/** `.` character */
|
||||
Chars[Chars["Dot"] = 46] = "Dot";
|
||||
/** `:` character */
|
||||
Chars[Chars["Colon"] = 58] = "Colon";
|
||||
/** `,` character */
|
||||
Chars[Chars["Comma"] = 44] = "Comma";
|
||||
/** `!` character */
|
||||
Chars[Chars["Excl"] = 33] = "Excl";
|
||||
/** `@` character */
|
||||
Chars[Chars["At"] = 64] = "At";
|
||||
/** `%` character */
|
||||
Chars[Chars["Percent"] = 37] = "Percent";
|
||||
/** `_` character */
|
||||
Chars[Chars["Underscore"] = 95] = "Underscore";
|
||||
/** `(` character */
|
||||
Chars[Chars["RoundBracketOpen"] = 40] = "RoundBracketOpen";
|
||||
/** `)` character */
|
||||
Chars[Chars["RoundBracketClose"] = 41] = "RoundBracketClose";
|
||||
/** `{` character */
|
||||
Chars[Chars["CurlyBracketOpen"] = 123] = "CurlyBracketOpen";
|
||||
/** `}` character */
|
||||
Chars[Chars["CurlyBracketClose"] = 125] = "CurlyBracketClose";
|
||||
/** `+` character */
|
||||
Chars[Chars["Sibling"] = 43] = "Sibling";
|
||||
/** `'` character */
|
||||
Chars[Chars["SingleQuote"] = 39] = "SingleQuote";
|
||||
/** `"` character */
|
||||
Chars[Chars["DoubleQuote"] = 34] = "DoubleQuote";
|
||||
/** `t` character */
|
||||
Chars[Chars["Transparent"] = 116] = "Transparent";
|
||||
/** `/` character */
|
||||
Chars[Chars["Slash"] = 47] = "Slash";
|
||||
})(Chars || (Chars = {}));
|
||||
|
||||
function tokenize(abbr, isValue) {
|
||||
let brackets = 0;
|
||||
let token;
|
||||
const scanner = new Scanner(abbr);
|
||||
const tokens = [];
|
||||
while (!scanner.eof()) {
|
||||
token = getToken(scanner, brackets === 0 && !isValue);
|
||||
if (!token) {
|
||||
throw scanner.error('Unexpected character');
|
||||
}
|
||||
if (token.type === 'Bracket') {
|
||||
if (!brackets && token.open) {
|
||||
mergeTokens(scanner, tokens);
|
||||
}
|
||||
brackets += token.open ? 1 : -1;
|
||||
if (brackets < 0) {
|
||||
throw scanner.error('Unexpected bracket', token.start);
|
||||
}
|
||||
}
|
||||
tokens.push(token);
|
||||
// Forcibly consume next operator after unit-less numeric value or color:
|
||||
// next dash `-` must be used as value delimiter
|
||||
if (shouldConsumeDashAfter(token) && (token = operator(scanner))) {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
/**
|
||||
* Returns next token from given scanner, if possible
|
||||
*/
|
||||
function getToken(scanner, short) {
|
||||
return field(scanner)
|
||||
|| customProperty(scanner)
|
||||
|| numberValue(scanner)
|
||||
|| colorValue(scanner)
|
||||
|| stringValue(scanner)
|
||||
|| bracket(scanner)
|
||||
|| operator(scanner)
|
||||
|| whiteSpace(scanner)
|
||||
|| literal(scanner, short);
|
||||
}
|
||||
function field(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Dollar) && scanner.eat(Chars.CurlyBracketOpen)) {
|
||||
scanner.start = scanner.pos;
|
||||
let index;
|
||||
let name = '';
|
||||
if (scanner.eatWhile(Scanner.isNumber)) {
|
||||
// It’s a field
|
||||
index = Number(scanner.current());
|
||||
name = scanner.eat(Chars.Colon) ? consumePlaceholder(scanner) : '';
|
||||
}
|
||||
else if (Scanner.isAlpha(scanner.peek())) {
|
||||
// It’s a variable
|
||||
name = consumePlaceholder(scanner);
|
||||
}
|
||||
if (scanner.eat(Chars.CurlyBracketClose)) {
|
||||
return {
|
||||
type: 'Field',
|
||||
index, name,
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
throw scanner.error('Expecting }');
|
||||
}
|
||||
// If we reached here then there’s no valid field here, revert
|
||||
// back to starting position
|
||||
scanner.pos = start;
|
||||
}
|
||||
/**
|
||||
* Consumes a placeholder: value right after `:` in field. Could be empty
|
||||
*/
|
||||
function consumePlaceholder(stream) {
|
||||
const stack = [];
|
||||
stream.start = stream.pos;
|
||||
while (!stream.eof()) {
|
||||
if (stream.eat(Chars.CurlyBracketOpen)) {
|
||||
stack.push(stream.pos);
|
||||
}
|
||||
else if (stream.eat(Chars.CurlyBracketClose)) {
|
||||
if (!stack.length) {
|
||||
stream.pos--;
|
||||
break;
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
else {
|
||||
stream.pos++;
|
||||
}
|
||||
}
|
||||
if (stack.length) {
|
||||
stream.pos = stack.pop();
|
||||
throw stream.error(`Expecting }`);
|
||||
}
|
||||
return stream.current();
|
||||
}
|
||||
/**
|
||||
* Consumes literal from given scanner
|
||||
* @param short Use short notation for consuming value.
|
||||
* The difference between “short” and “full” notation is that first one uses
|
||||
* alpha characters only and used for extracting keywords from abbreviation,
|
||||
* while “full” notation also supports numbers and dashes
|
||||
*/
|
||||
function literal(scanner, short) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(isIdentPrefix)) {
|
||||
// SCSS or LESS variable
|
||||
// NB a bit dirty hack: if abbreviation starts with identifier prefix,
|
||||
// consume alpha characters only to allow embedded variables
|
||||
scanner.eatWhile(start ? isKeyword : isLiteral$1);
|
||||
}
|
||||
else if (scanner.eat(Scanner.isAlphaWord)) {
|
||||
scanner.eatWhile(short ? isLiteral$1 : isKeyword);
|
||||
}
|
||||
else {
|
||||
// Allow dots only at the beginning of literal
|
||||
scanner.eat(Chars.Dot);
|
||||
scanner.eatWhile(isLiteral$1);
|
||||
}
|
||||
if (start !== scanner.pos) {
|
||||
scanner.start = start;
|
||||
return createLiteral(scanner, scanner.start = start);
|
||||
}
|
||||
}
|
||||
function createLiteral(scanner, start = scanner.start, end = scanner.pos) {
|
||||
return {
|
||||
type: 'Literal',
|
||||
value: scanner.substring(start, end),
|
||||
start,
|
||||
end
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Consumes numeric CSS value (number with optional unit) from current stream,
|
||||
* if possible
|
||||
*/
|
||||
function numberValue(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (consumeNumber(scanner)) {
|
||||
scanner.start = start;
|
||||
const rawValue = scanner.current();
|
||||
// eat unit, which can be a % or alpha word
|
||||
scanner.start = scanner.pos;
|
||||
scanner.eat(Chars.Percent) || scanner.eatWhile(Scanner.isAlphaWord);
|
||||
return {
|
||||
type: 'NumberValue',
|
||||
value: Number(rawValue),
|
||||
rawValue,
|
||||
unit: scanner.current(),
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes quoted string value from given scanner
|
||||
*/
|
||||
function stringValue(scanner) {
|
||||
const ch = scanner.peek();
|
||||
const start = scanner.pos;
|
||||
let finished = false;
|
||||
if (Scanner.isQuote(ch)) {
|
||||
scanner.pos++;
|
||||
while (!scanner.eof()) {
|
||||
// Do not throw error on malformed string
|
||||
if (scanner.eat(ch)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
scanner.pos++;
|
||||
}
|
||||
}
|
||||
scanner.start = start;
|
||||
return {
|
||||
type: 'StringValue',
|
||||
value: scanner.substring(start + 1, scanner.pos - (finished ? 1 : 0)),
|
||||
quote: ch === Chars.SingleQuote ? 'single' : 'double',
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes a color token from given string
|
||||
*/
|
||||
function colorValue(scanner) {
|
||||
// supported color variations:
|
||||
// #abc → #aabbccc
|
||||
// #0 → #000000
|
||||
// #fff.5 → rgba(255, 255, 255, 0.5)
|
||||
// #t → transparent
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Hash)) {
|
||||
const valueStart = scanner.pos;
|
||||
let color = '';
|
||||
let alpha = '';
|
||||
if (scanner.eatWhile(isHex)) {
|
||||
color = scanner.substring(valueStart, scanner.pos);
|
||||
alpha = colorAlpha(scanner);
|
||||
}
|
||||
else if (scanner.eat(Chars.Transparent)) {
|
||||
color = '0';
|
||||
alpha = colorAlpha(scanner) || '0';
|
||||
}
|
||||
else {
|
||||
alpha = colorAlpha(scanner);
|
||||
}
|
||||
if (color || alpha || scanner.eof()) {
|
||||
const { r, g, b, a } = parseColor(color, alpha);
|
||||
return {
|
||||
type: 'ColorValue',
|
||||
r, g, b, a,
|
||||
raw: scanner.substring(start + 1, scanner.pos),
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
else {
|
||||
// Consumed # but no actual value: invalid color value, treat it as literal
|
||||
return createLiteral(scanner, start);
|
||||
}
|
||||
}
|
||||
scanner.pos = start;
|
||||
}
|
||||
/**
|
||||
* Consumes alpha value of color: `.1`
|
||||
*/
|
||||
function colorAlpha(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Dot)) {
|
||||
scanner.start = start;
|
||||
if (scanner.eatWhile(Scanner.isNumber)) {
|
||||
return scanner.current();
|
||||
}
|
||||
return '1';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* Consumes white space characters as string literal from given scanner
|
||||
*/
|
||||
function whiteSpace(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eatWhile(Scanner.isSpace)) {
|
||||
return {
|
||||
type: 'WhiteSpace',
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes custom CSS property: --foo-bar
|
||||
*/
|
||||
function customProperty(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Dash) && scanner.eat(Chars.Dash)) {
|
||||
scanner.start = start;
|
||||
scanner.eatWhile(isKeyword);
|
||||
return {
|
||||
type: 'CustomProperty',
|
||||
value: scanner.current(),
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
scanner.pos = start;
|
||||
}
|
||||
/**
|
||||
* Consumes bracket from given scanner
|
||||
*/
|
||||
function bracket(scanner) {
|
||||
const ch = scanner.peek();
|
||||
if (isBracket$1(ch)) {
|
||||
return {
|
||||
type: 'Bracket',
|
||||
open: ch === Chars.RoundBracketOpen,
|
||||
start: scanner.pos++,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes operator from given scanner
|
||||
*/
|
||||
function operator(scanner) {
|
||||
const op = operatorType(scanner.peek());
|
||||
if (op) {
|
||||
return {
|
||||
type: 'Operator',
|
||||
operator: op,
|
||||
start: scanner.pos++,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Eats number value from given stream
|
||||
* @return Returns `true` if number was consumed
|
||||
*/
|
||||
function consumeNumber(stream) {
|
||||
const start = stream.pos;
|
||||
stream.eat(Chars.Dash);
|
||||
const afterNegative = stream.pos;
|
||||
const hasDecimal = stream.eatWhile(Scanner.isNumber);
|
||||
const prevPos = stream.pos;
|
||||
if (stream.eat(Chars.Dot)) {
|
||||
// It’s perfectly valid to have numbers like `1.`, which enforces
|
||||
// value to float unit type
|
||||
const hasFloat = stream.eatWhile(Scanner.isNumber);
|
||||
if (!hasDecimal && !hasFloat) {
|
||||
// Lone dot
|
||||
stream.pos = prevPos;
|
||||
}
|
||||
}
|
||||
// Edge case: consumed dash only: not a number, bail-out
|
||||
if (stream.pos === afterNegative) {
|
||||
stream.pos = start;
|
||||
}
|
||||
return stream.pos !== start;
|
||||
}
|
||||
function isIdentPrefix(code) {
|
||||
return code === Chars.At || code === Chars.Dollar;
|
||||
}
|
||||
/**
|
||||
* If given character is an operator, returns it’s type
|
||||
*/
|
||||
function operatorType(ch) {
|
||||
return (ch === Chars.Sibling && exports.OperatorType.Sibling)
|
||||
|| (ch === Chars.Excl && exports.OperatorType.Important)
|
||||
|| (ch === Chars.Comma && exports.OperatorType.ArgumentDelimiter)
|
||||
|| (ch === Chars.Colon && exports.OperatorType.PropertyDelimiter)
|
||||
|| (ch === Chars.Dash && exports.OperatorType.ValueDelimiter)
|
||||
|| void 0;
|
||||
}
|
||||
/**
|
||||
* Check if given code is a hex value (/0-9a-f/)
|
||||
*/
|
||||
function isHex(code) {
|
||||
return Scanner.isNumber(code) || Scanner.isAlpha(code, 65, 70); // A-F
|
||||
}
|
||||
function isKeyword(code) {
|
||||
return Scanner.isAlphaNumericWord(code) || code === Chars.Dash;
|
||||
}
|
||||
function isBracket$1(code) {
|
||||
return code === Chars.RoundBracketOpen || code === Chars.RoundBracketClose;
|
||||
}
|
||||
function isLiteral$1(code) {
|
||||
return Scanner.isAlphaWord(code) || code === Chars.Percent || code === Chars.Slash;
|
||||
}
|
||||
/**
|
||||
* Parses given color value from abbreviation into RGBA format
|
||||
*/
|
||||
function parseColor(value, alpha) {
|
||||
let r = '0';
|
||||
let g = '0';
|
||||
let b = '0';
|
||||
let a = Number(alpha != null && alpha !== '' ? alpha : 1);
|
||||
if (value === 't') {
|
||||
a = 0;
|
||||
}
|
||||
else {
|
||||
switch (value.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
r = g = b = value + value;
|
||||
break;
|
||||
case 2:
|
||||
r = g = b = value;
|
||||
break;
|
||||
case 3:
|
||||
r = value[0] + value[0];
|
||||
g = value[1] + value[1];
|
||||
b = value[2] + value[2];
|
||||
break;
|
||||
default:
|
||||
value += value;
|
||||
r = value.slice(0, 2);
|
||||
g = value.slice(2, 4);
|
||||
b = value.slice(4, 6);
|
||||
}
|
||||
}
|
||||
return {
|
||||
r: parseInt(r, 16),
|
||||
g: parseInt(g, 16),
|
||||
b: parseInt(b, 16),
|
||||
a
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Check if scanner reader must consume dash after given token.
|
||||
* Used in cases where user must explicitly separate numeric values
|
||||
*/
|
||||
function shouldConsumeDashAfter(token) {
|
||||
return token.type === 'ColorValue' || (token.type === 'NumberValue' && !token.unit);
|
||||
}
|
||||
/**
|
||||
* Merges last adjacent tokens into a single literal.
|
||||
* This function is used to overcome edge case when function name was parsed
|
||||
* as a list of separate tokens. For example, a `scale3d()` value will be
|
||||
* parsed as literal and number tokens (`scale` and `3d`) which is a perfectly
|
||||
* valid abbreviation but undesired result. This function will detect last adjacent
|
||||
* literal and number values and combine them into single literal
|
||||
*/
|
||||
function mergeTokens(scanner, tokens) {
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
while (tokens.length) {
|
||||
const token = last(tokens);
|
||||
if (token.type === 'Literal' || token.type === 'NumberValue') {
|
||||
start = token.start;
|
||||
if (!end) {
|
||||
end = token.end;
|
||||
}
|
||||
tokens.pop();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start !== end) {
|
||||
tokens.push(createLiteral(scanner, start, end));
|
||||
}
|
||||
}
|
||||
function last(arr) {
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
function tokenScanner(tokens) {
|
||||
return {
|
||||
tokens,
|
||||
start: 0,
|
||||
pos: 0,
|
||||
size: tokens.length
|
||||
};
|
||||
}
|
||||
function peek(scanner) {
|
||||
return scanner.tokens[scanner.pos];
|
||||
}
|
||||
function readable(scanner) {
|
||||
return scanner.pos < scanner.size;
|
||||
}
|
||||
function consume(scanner, test) {
|
||||
if (test(peek(scanner))) {
|
||||
scanner.pos++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function error(scanner, message, token = peek(scanner)) {
|
||||
if (token && token.start != null) {
|
||||
message += ` at ${token.start}`;
|
||||
}
|
||||
const err = new Error(message);
|
||||
err['pos'] = token && token.start;
|
||||
return err;
|
||||
}
|
||||
|
||||
function parser(tokens, options = {}) {
|
||||
const scanner = tokenScanner(tokens);
|
||||
const result = [];
|
||||
let property;
|
||||
while (readable(scanner)) {
|
||||
if (property = consumeProperty(scanner, options)) {
|
||||
result.push(property);
|
||||
}
|
||||
else if (!consume(scanner, isSiblingOperator)) {
|
||||
throw error(scanner, 'Unexpected token');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Consumes single CSS property
|
||||
*/
|
||||
function consumeProperty(scanner, options) {
|
||||
let name;
|
||||
let important = false;
|
||||
let valueFragment;
|
||||
const value = [];
|
||||
const token = peek(scanner);
|
||||
const valueMode = !!options.value;
|
||||
if (!valueMode && isLiteral(token) && !isFunctionStart(scanner)) {
|
||||
scanner.pos++;
|
||||
name = token.value;
|
||||
// Consume any following value delimiter after property name
|
||||
consume(scanner, isValueDelimiter);
|
||||
}
|
||||
// Skip whitespace right after property name, if any
|
||||
if (valueMode) {
|
||||
consume(scanner, isWhiteSpace);
|
||||
}
|
||||
while (readable(scanner)) {
|
||||
if (consume(scanner, isImportant)) {
|
||||
important = true;
|
||||
}
|
||||
else if (valueFragment = consumeValue(scanner, valueMode)) {
|
||||
value.push(valueFragment);
|
||||
}
|
||||
else if (!consume(scanner, isFragmentDelimiter)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (name || value.length || important) {
|
||||
return { name, value, important };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes single value fragment, e.g. all value tokens before comma
|
||||
*/
|
||||
function consumeValue(scanner, inArgument) {
|
||||
const result = [];
|
||||
let token;
|
||||
let args;
|
||||
while (readable(scanner)) {
|
||||
token = peek(scanner);
|
||||
if (isValue(token)) {
|
||||
scanner.pos++;
|
||||
if (isLiteral(token) && (args = consumeArguments(scanner))) {
|
||||
result.push({
|
||||
type: 'FunctionCall',
|
||||
name: token.value,
|
||||
arguments: args
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.push(token);
|
||||
}
|
||||
}
|
||||
else if (isValueDelimiter(token) || (inArgument && isWhiteSpace(token))) {
|
||||
scanner.pos++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result.length
|
||||
? { type: 'CSSValue', value: result }
|
||||
: void 0;
|
||||
}
|
||||
function consumeArguments(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (consume(scanner, isOpenBracket)) {
|
||||
const args = [];
|
||||
let value;
|
||||
while (readable(scanner) && !consume(scanner, isCloseBracket)) {
|
||||
if (value = consumeValue(scanner, true)) {
|
||||
args.push(value);
|
||||
}
|
||||
else if (!consume(scanner, isWhiteSpace) && !consume(scanner, isArgumentDelimiter)) {
|
||||
throw error(scanner, 'Unexpected token');
|
||||
}
|
||||
}
|
||||
scanner.start = start;
|
||||
return args;
|
||||
}
|
||||
}
|
||||
function isLiteral(token) {
|
||||
return token && token.type === 'Literal';
|
||||
}
|
||||
function isBracket(token, open) {
|
||||
return token && token.type === 'Bracket' && (open == null || token.open === open);
|
||||
}
|
||||
function isOpenBracket(token) {
|
||||
return isBracket(token, true);
|
||||
}
|
||||
function isCloseBracket(token) {
|
||||
return isBracket(token, false);
|
||||
}
|
||||
function isWhiteSpace(token) {
|
||||
return token && token.type === 'WhiteSpace';
|
||||
}
|
||||
function isOperator(token, operator) {
|
||||
return token && token.type === 'Operator' && (!operator || token.operator === operator);
|
||||
}
|
||||
function isSiblingOperator(token) {
|
||||
return isOperator(token, exports.OperatorType.Sibling);
|
||||
}
|
||||
function isArgumentDelimiter(token) {
|
||||
return isOperator(token, exports.OperatorType.ArgumentDelimiter);
|
||||
}
|
||||
function isFragmentDelimiter(token) {
|
||||
return isArgumentDelimiter(token);
|
||||
}
|
||||
function isImportant(token) {
|
||||
return isOperator(token, exports.OperatorType.Important);
|
||||
}
|
||||
function isValue(token) {
|
||||
return token.type === 'StringValue'
|
||||
|| token.type === 'ColorValue'
|
||||
|| token.type === 'NumberValue'
|
||||
|| token.type === 'Literal'
|
||||
|| token.type === 'Field'
|
||||
|| token.type === 'CustomProperty';
|
||||
}
|
||||
function isValueDelimiter(token) {
|
||||
return isOperator(token, exports.OperatorType.PropertyDelimiter)
|
||||
|| isOperator(token, exports.OperatorType.ValueDelimiter);
|
||||
}
|
||||
function isFunctionStart(scanner) {
|
||||
const t1 = scanner.tokens[scanner.pos];
|
||||
const t2 = scanner.tokens[scanner.pos + 1];
|
||||
return t1 && t2 && isLiteral(t1) && t2.type === 'Bracket';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses given abbreviation into property set
|
||||
*/
|
||||
function parse(abbr, options) {
|
||||
try {
|
||||
const tokens = typeof abbr === 'string' ? tokenize(abbr, options && options.value) : abbr;
|
||||
return parser(tokens, options);
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof Scanner.ScannerError && typeof abbr === 'string') {
|
||||
err.message += `\n${abbr}\n${'-'.repeat(err.pos)}^`;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
exports.default = parse;
|
||||
exports.getToken = getToken;
|
||||
exports.parser = parser;
|
||||
exports.tokenize = tokenize;
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
1
node_modules/@emmetio/css-abbreviation/dist/index.cjs.map
generated
vendored
Normal file
1
node_modules/@emmetio/css-abbreviation/dist/index.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
10
node_modules/@emmetio/css-abbreviation/dist/index.d.ts
generated
vendored
Normal file
10
node_modules/@emmetio/css-abbreviation/dist/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import tokenize, { getToken, type AllTokens } from './tokenizer/index.js';
|
||||
import parser, { type CSSProperty, type ParseOptions } from './parser/index.js';
|
||||
export { tokenize, getToken, parser };
|
||||
export * from './tokenizer/tokens.js';
|
||||
export type { CSSProperty, CSSValue, ParseOptions, FunctionCall, Value } from './parser/index.js';
|
||||
export type CSSAbbreviation = CSSProperty[];
|
||||
/**
|
||||
* Parses given abbreviation into property set
|
||||
*/
|
||||
export default function parse(abbr: string | AllTokens[], options?: ParseOptions): CSSAbbreviation;
|
||||
680
node_modules/@emmetio/css-abbreviation/dist/index.js
generated
vendored
Normal file
680
node_modules/@emmetio/css-abbreviation/dist/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,680 @@
|
|||
import Scanner, { isNumber, isAlpha, isAlphaWord, isQuote, isSpace, isAlphaNumericWord, ScannerError } from '@emmetio/scanner';
|
||||
|
||||
var OperatorType;
|
||||
(function (OperatorType) {
|
||||
OperatorType["Sibling"] = "+";
|
||||
OperatorType["Important"] = "!";
|
||||
OperatorType["ArgumentDelimiter"] = ",";
|
||||
OperatorType["ValueDelimiter"] = "-";
|
||||
OperatorType["PropertyDelimiter"] = ":";
|
||||
})(OperatorType || (OperatorType = {}));
|
||||
|
||||
var Chars;
|
||||
(function (Chars) {
|
||||
/** `#` character */
|
||||
Chars[Chars["Hash"] = 35] = "Hash";
|
||||
/** `$` character */
|
||||
Chars[Chars["Dollar"] = 36] = "Dollar";
|
||||
/** `-` character */
|
||||
Chars[Chars["Dash"] = 45] = "Dash";
|
||||
/** `.` character */
|
||||
Chars[Chars["Dot"] = 46] = "Dot";
|
||||
/** `:` character */
|
||||
Chars[Chars["Colon"] = 58] = "Colon";
|
||||
/** `,` character */
|
||||
Chars[Chars["Comma"] = 44] = "Comma";
|
||||
/** `!` character */
|
||||
Chars[Chars["Excl"] = 33] = "Excl";
|
||||
/** `@` character */
|
||||
Chars[Chars["At"] = 64] = "At";
|
||||
/** `%` character */
|
||||
Chars[Chars["Percent"] = 37] = "Percent";
|
||||
/** `_` character */
|
||||
Chars[Chars["Underscore"] = 95] = "Underscore";
|
||||
/** `(` character */
|
||||
Chars[Chars["RoundBracketOpen"] = 40] = "RoundBracketOpen";
|
||||
/** `)` character */
|
||||
Chars[Chars["RoundBracketClose"] = 41] = "RoundBracketClose";
|
||||
/** `{` character */
|
||||
Chars[Chars["CurlyBracketOpen"] = 123] = "CurlyBracketOpen";
|
||||
/** `}` character */
|
||||
Chars[Chars["CurlyBracketClose"] = 125] = "CurlyBracketClose";
|
||||
/** `+` character */
|
||||
Chars[Chars["Sibling"] = 43] = "Sibling";
|
||||
/** `'` character */
|
||||
Chars[Chars["SingleQuote"] = 39] = "SingleQuote";
|
||||
/** `"` character */
|
||||
Chars[Chars["DoubleQuote"] = 34] = "DoubleQuote";
|
||||
/** `t` character */
|
||||
Chars[Chars["Transparent"] = 116] = "Transparent";
|
||||
/** `/` character */
|
||||
Chars[Chars["Slash"] = 47] = "Slash";
|
||||
})(Chars || (Chars = {}));
|
||||
|
||||
function tokenize(abbr, isValue) {
|
||||
let brackets = 0;
|
||||
let token;
|
||||
const scanner = new Scanner(abbr);
|
||||
const tokens = [];
|
||||
while (!scanner.eof()) {
|
||||
token = getToken(scanner, brackets === 0 && !isValue);
|
||||
if (!token) {
|
||||
throw scanner.error('Unexpected character');
|
||||
}
|
||||
if (token.type === 'Bracket') {
|
||||
if (!brackets && token.open) {
|
||||
mergeTokens(scanner, tokens);
|
||||
}
|
||||
brackets += token.open ? 1 : -1;
|
||||
if (brackets < 0) {
|
||||
throw scanner.error('Unexpected bracket', token.start);
|
||||
}
|
||||
}
|
||||
tokens.push(token);
|
||||
// Forcibly consume next operator after unit-less numeric value or color:
|
||||
// next dash `-` must be used as value delimiter
|
||||
if (shouldConsumeDashAfter(token) && (token = operator(scanner))) {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
/**
|
||||
* Returns next token from given scanner, if possible
|
||||
*/
|
||||
function getToken(scanner, short) {
|
||||
return field(scanner)
|
||||
|| customProperty(scanner)
|
||||
|| numberValue(scanner)
|
||||
|| colorValue(scanner)
|
||||
|| stringValue(scanner)
|
||||
|| bracket(scanner)
|
||||
|| operator(scanner)
|
||||
|| whiteSpace(scanner)
|
||||
|| literal(scanner, short);
|
||||
}
|
||||
function field(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Dollar) && scanner.eat(Chars.CurlyBracketOpen)) {
|
||||
scanner.start = scanner.pos;
|
||||
let index;
|
||||
let name = '';
|
||||
if (scanner.eatWhile(isNumber)) {
|
||||
// It’s a field
|
||||
index = Number(scanner.current());
|
||||
name = scanner.eat(Chars.Colon) ? consumePlaceholder(scanner) : '';
|
||||
}
|
||||
else if (isAlpha(scanner.peek())) {
|
||||
// It’s a variable
|
||||
name = consumePlaceholder(scanner);
|
||||
}
|
||||
if (scanner.eat(Chars.CurlyBracketClose)) {
|
||||
return {
|
||||
type: 'Field',
|
||||
index, name,
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
throw scanner.error('Expecting }');
|
||||
}
|
||||
// If we reached here then there’s no valid field here, revert
|
||||
// back to starting position
|
||||
scanner.pos = start;
|
||||
}
|
||||
/**
|
||||
* Consumes a placeholder: value right after `:` in field. Could be empty
|
||||
*/
|
||||
function consumePlaceholder(stream) {
|
||||
const stack = [];
|
||||
stream.start = stream.pos;
|
||||
while (!stream.eof()) {
|
||||
if (stream.eat(Chars.CurlyBracketOpen)) {
|
||||
stack.push(stream.pos);
|
||||
}
|
||||
else if (stream.eat(Chars.CurlyBracketClose)) {
|
||||
if (!stack.length) {
|
||||
stream.pos--;
|
||||
break;
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
else {
|
||||
stream.pos++;
|
||||
}
|
||||
}
|
||||
if (stack.length) {
|
||||
stream.pos = stack.pop();
|
||||
throw stream.error(`Expecting }`);
|
||||
}
|
||||
return stream.current();
|
||||
}
|
||||
/**
|
||||
* Consumes literal from given scanner
|
||||
* @param short Use short notation for consuming value.
|
||||
* The difference between “short” and “full” notation is that first one uses
|
||||
* alpha characters only and used for extracting keywords from abbreviation,
|
||||
* while “full” notation also supports numbers and dashes
|
||||
*/
|
||||
function literal(scanner, short) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(isIdentPrefix)) {
|
||||
// SCSS or LESS variable
|
||||
// NB a bit dirty hack: if abbreviation starts with identifier prefix,
|
||||
// consume alpha characters only to allow embedded variables
|
||||
scanner.eatWhile(start ? isKeyword : isLiteral$1);
|
||||
}
|
||||
else if (scanner.eat(isAlphaWord)) {
|
||||
scanner.eatWhile(short ? isLiteral$1 : isKeyword);
|
||||
}
|
||||
else {
|
||||
// Allow dots only at the beginning of literal
|
||||
scanner.eat(Chars.Dot);
|
||||
scanner.eatWhile(isLiteral$1);
|
||||
}
|
||||
if (start !== scanner.pos) {
|
||||
scanner.start = start;
|
||||
return createLiteral(scanner, scanner.start = start);
|
||||
}
|
||||
}
|
||||
function createLiteral(scanner, start = scanner.start, end = scanner.pos) {
|
||||
return {
|
||||
type: 'Literal',
|
||||
value: scanner.substring(start, end),
|
||||
start,
|
||||
end
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Consumes numeric CSS value (number with optional unit) from current stream,
|
||||
* if possible
|
||||
*/
|
||||
function numberValue(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (consumeNumber(scanner)) {
|
||||
scanner.start = start;
|
||||
const rawValue = scanner.current();
|
||||
// eat unit, which can be a % or alpha word
|
||||
scanner.start = scanner.pos;
|
||||
scanner.eat(Chars.Percent) || scanner.eatWhile(isAlphaWord);
|
||||
return {
|
||||
type: 'NumberValue',
|
||||
value: Number(rawValue),
|
||||
rawValue,
|
||||
unit: scanner.current(),
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes quoted string value from given scanner
|
||||
*/
|
||||
function stringValue(scanner) {
|
||||
const ch = scanner.peek();
|
||||
const start = scanner.pos;
|
||||
let finished = false;
|
||||
if (isQuote(ch)) {
|
||||
scanner.pos++;
|
||||
while (!scanner.eof()) {
|
||||
// Do not throw error on malformed string
|
||||
if (scanner.eat(ch)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
scanner.pos++;
|
||||
}
|
||||
}
|
||||
scanner.start = start;
|
||||
return {
|
||||
type: 'StringValue',
|
||||
value: scanner.substring(start + 1, scanner.pos - (finished ? 1 : 0)),
|
||||
quote: ch === Chars.SingleQuote ? 'single' : 'double',
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes a color token from given string
|
||||
*/
|
||||
function colorValue(scanner) {
|
||||
// supported color variations:
|
||||
// #abc → #aabbccc
|
||||
// #0 → #000000
|
||||
// #fff.5 → rgba(255, 255, 255, 0.5)
|
||||
// #t → transparent
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Hash)) {
|
||||
const valueStart = scanner.pos;
|
||||
let color = '';
|
||||
let alpha = '';
|
||||
if (scanner.eatWhile(isHex)) {
|
||||
color = scanner.substring(valueStart, scanner.pos);
|
||||
alpha = colorAlpha(scanner);
|
||||
}
|
||||
else if (scanner.eat(Chars.Transparent)) {
|
||||
color = '0';
|
||||
alpha = colorAlpha(scanner) || '0';
|
||||
}
|
||||
else {
|
||||
alpha = colorAlpha(scanner);
|
||||
}
|
||||
if (color || alpha || scanner.eof()) {
|
||||
const { r, g, b, a } = parseColor(color, alpha);
|
||||
return {
|
||||
type: 'ColorValue',
|
||||
r, g, b, a,
|
||||
raw: scanner.substring(start + 1, scanner.pos),
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
else {
|
||||
// Consumed # but no actual value: invalid color value, treat it as literal
|
||||
return createLiteral(scanner, start);
|
||||
}
|
||||
}
|
||||
scanner.pos = start;
|
||||
}
|
||||
/**
|
||||
* Consumes alpha value of color: `.1`
|
||||
*/
|
||||
function colorAlpha(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Dot)) {
|
||||
scanner.start = start;
|
||||
if (scanner.eatWhile(isNumber)) {
|
||||
return scanner.current();
|
||||
}
|
||||
return '1';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* Consumes white space characters as string literal from given scanner
|
||||
*/
|
||||
function whiteSpace(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eatWhile(isSpace)) {
|
||||
return {
|
||||
type: 'WhiteSpace',
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes custom CSS property: --foo-bar
|
||||
*/
|
||||
function customProperty(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (scanner.eat(Chars.Dash) && scanner.eat(Chars.Dash)) {
|
||||
scanner.start = start;
|
||||
scanner.eatWhile(isKeyword);
|
||||
return {
|
||||
type: 'CustomProperty',
|
||||
value: scanner.current(),
|
||||
start,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
scanner.pos = start;
|
||||
}
|
||||
/**
|
||||
* Consumes bracket from given scanner
|
||||
*/
|
||||
function bracket(scanner) {
|
||||
const ch = scanner.peek();
|
||||
if (isBracket$1(ch)) {
|
||||
return {
|
||||
type: 'Bracket',
|
||||
open: ch === Chars.RoundBracketOpen,
|
||||
start: scanner.pos++,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes operator from given scanner
|
||||
*/
|
||||
function operator(scanner) {
|
||||
const op = operatorType(scanner.peek());
|
||||
if (op) {
|
||||
return {
|
||||
type: 'Operator',
|
||||
operator: op,
|
||||
start: scanner.pos++,
|
||||
end: scanner.pos
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Eats number value from given stream
|
||||
* @return Returns `true` if number was consumed
|
||||
*/
|
||||
function consumeNumber(stream) {
|
||||
const start = stream.pos;
|
||||
stream.eat(Chars.Dash);
|
||||
const afterNegative = stream.pos;
|
||||
const hasDecimal = stream.eatWhile(isNumber);
|
||||
const prevPos = stream.pos;
|
||||
if (stream.eat(Chars.Dot)) {
|
||||
// It’s perfectly valid to have numbers like `1.`, which enforces
|
||||
// value to float unit type
|
||||
const hasFloat = stream.eatWhile(isNumber);
|
||||
if (!hasDecimal && !hasFloat) {
|
||||
// Lone dot
|
||||
stream.pos = prevPos;
|
||||
}
|
||||
}
|
||||
// Edge case: consumed dash only: not a number, bail-out
|
||||
if (stream.pos === afterNegative) {
|
||||
stream.pos = start;
|
||||
}
|
||||
return stream.pos !== start;
|
||||
}
|
||||
function isIdentPrefix(code) {
|
||||
return code === Chars.At || code === Chars.Dollar;
|
||||
}
|
||||
/**
|
||||
* If given character is an operator, returns it’s type
|
||||
*/
|
||||
function operatorType(ch) {
|
||||
return (ch === Chars.Sibling && OperatorType.Sibling)
|
||||
|| (ch === Chars.Excl && OperatorType.Important)
|
||||
|| (ch === Chars.Comma && OperatorType.ArgumentDelimiter)
|
||||
|| (ch === Chars.Colon && OperatorType.PropertyDelimiter)
|
||||
|| (ch === Chars.Dash && OperatorType.ValueDelimiter)
|
||||
|| void 0;
|
||||
}
|
||||
/**
|
||||
* Check if given code is a hex value (/0-9a-f/)
|
||||
*/
|
||||
function isHex(code) {
|
||||
return isNumber(code) || isAlpha(code, 65, 70); // A-F
|
||||
}
|
||||
function isKeyword(code) {
|
||||
return isAlphaNumericWord(code) || code === Chars.Dash;
|
||||
}
|
||||
function isBracket$1(code) {
|
||||
return code === Chars.RoundBracketOpen || code === Chars.RoundBracketClose;
|
||||
}
|
||||
function isLiteral$1(code) {
|
||||
return isAlphaWord(code) || code === Chars.Percent || code === Chars.Slash;
|
||||
}
|
||||
/**
|
||||
* Parses given color value from abbreviation into RGBA format
|
||||
*/
|
||||
function parseColor(value, alpha) {
|
||||
let r = '0';
|
||||
let g = '0';
|
||||
let b = '0';
|
||||
let a = Number(alpha != null && alpha !== '' ? alpha : 1);
|
||||
if (value === 't') {
|
||||
a = 0;
|
||||
}
|
||||
else {
|
||||
switch (value.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
r = g = b = value + value;
|
||||
break;
|
||||
case 2:
|
||||
r = g = b = value;
|
||||
break;
|
||||
case 3:
|
||||
r = value[0] + value[0];
|
||||
g = value[1] + value[1];
|
||||
b = value[2] + value[2];
|
||||
break;
|
||||
default:
|
||||
value += value;
|
||||
r = value.slice(0, 2);
|
||||
g = value.slice(2, 4);
|
||||
b = value.slice(4, 6);
|
||||
}
|
||||
}
|
||||
return {
|
||||
r: parseInt(r, 16),
|
||||
g: parseInt(g, 16),
|
||||
b: parseInt(b, 16),
|
||||
a
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Check if scanner reader must consume dash after given token.
|
||||
* Used in cases where user must explicitly separate numeric values
|
||||
*/
|
||||
function shouldConsumeDashAfter(token) {
|
||||
return token.type === 'ColorValue' || (token.type === 'NumberValue' && !token.unit);
|
||||
}
|
||||
/**
|
||||
* Merges last adjacent tokens into a single literal.
|
||||
* This function is used to overcome edge case when function name was parsed
|
||||
* as a list of separate tokens. For example, a `scale3d()` value will be
|
||||
* parsed as literal and number tokens (`scale` and `3d`) which is a perfectly
|
||||
* valid abbreviation but undesired result. This function will detect last adjacent
|
||||
* literal and number values and combine them into single literal
|
||||
*/
|
||||
function mergeTokens(scanner, tokens) {
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
while (tokens.length) {
|
||||
const token = last(tokens);
|
||||
if (token.type === 'Literal' || token.type === 'NumberValue') {
|
||||
start = token.start;
|
||||
if (!end) {
|
||||
end = token.end;
|
||||
}
|
||||
tokens.pop();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start !== end) {
|
||||
tokens.push(createLiteral(scanner, start, end));
|
||||
}
|
||||
}
|
||||
function last(arr) {
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
function tokenScanner(tokens) {
|
||||
return {
|
||||
tokens,
|
||||
start: 0,
|
||||
pos: 0,
|
||||
size: tokens.length
|
||||
};
|
||||
}
|
||||
function peek(scanner) {
|
||||
return scanner.tokens[scanner.pos];
|
||||
}
|
||||
function readable(scanner) {
|
||||
return scanner.pos < scanner.size;
|
||||
}
|
||||
function consume(scanner, test) {
|
||||
if (test(peek(scanner))) {
|
||||
scanner.pos++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function error(scanner, message, token = peek(scanner)) {
|
||||
if (token && token.start != null) {
|
||||
message += ` at ${token.start}`;
|
||||
}
|
||||
const err = new Error(message);
|
||||
err['pos'] = token && token.start;
|
||||
return err;
|
||||
}
|
||||
|
||||
function parser(tokens, options = {}) {
|
||||
const scanner = tokenScanner(tokens);
|
||||
const result = [];
|
||||
let property;
|
||||
while (readable(scanner)) {
|
||||
if (property = consumeProperty(scanner, options)) {
|
||||
result.push(property);
|
||||
}
|
||||
else if (!consume(scanner, isSiblingOperator)) {
|
||||
throw error(scanner, 'Unexpected token');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Consumes single CSS property
|
||||
*/
|
||||
function consumeProperty(scanner, options) {
|
||||
let name;
|
||||
let important = false;
|
||||
let valueFragment;
|
||||
const value = [];
|
||||
const token = peek(scanner);
|
||||
const valueMode = !!options.value;
|
||||
if (!valueMode && isLiteral(token) && !isFunctionStart(scanner)) {
|
||||
scanner.pos++;
|
||||
name = token.value;
|
||||
// Consume any following value delimiter after property name
|
||||
consume(scanner, isValueDelimiter);
|
||||
}
|
||||
// Skip whitespace right after property name, if any
|
||||
if (valueMode) {
|
||||
consume(scanner, isWhiteSpace);
|
||||
}
|
||||
while (readable(scanner)) {
|
||||
if (consume(scanner, isImportant)) {
|
||||
important = true;
|
||||
}
|
||||
else if (valueFragment = consumeValue(scanner, valueMode)) {
|
||||
value.push(valueFragment);
|
||||
}
|
||||
else if (!consume(scanner, isFragmentDelimiter)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (name || value.length || important) {
|
||||
return { name, value, important };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Consumes single value fragment, e.g. all value tokens before comma
|
||||
*/
|
||||
function consumeValue(scanner, inArgument) {
|
||||
const result = [];
|
||||
let token;
|
||||
let args;
|
||||
while (readable(scanner)) {
|
||||
token = peek(scanner);
|
||||
if (isValue(token)) {
|
||||
scanner.pos++;
|
||||
if (isLiteral(token) && (args = consumeArguments(scanner))) {
|
||||
result.push({
|
||||
type: 'FunctionCall',
|
||||
name: token.value,
|
||||
arguments: args
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.push(token);
|
||||
}
|
||||
}
|
||||
else if (isValueDelimiter(token) || (inArgument && isWhiteSpace(token))) {
|
||||
scanner.pos++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result.length
|
||||
? { type: 'CSSValue', value: result }
|
||||
: void 0;
|
||||
}
|
||||
function consumeArguments(scanner) {
|
||||
const start = scanner.pos;
|
||||
if (consume(scanner, isOpenBracket)) {
|
||||
const args = [];
|
||||
let value;
|
||||
while (readable(scanner) && !consume(scanner, isCloseBracket)) {
|
||||
if (value = consumeValue(scanner, true)) {
|
||||
args.push(value);
|
||||
}
|
||||
else if (!consume(scanner, isWhiteSpace) && !consume(scanner, isArgumentDelimiter)) {
|
||||
throw error(scanner, 'Unexpected token');
|
||||
}
|
||||
}
|
||||
scanner.start = start;
|
||||
return args;
|
||||
}
|
||||
}
|
||||
function isLiteral(token) {
|
||||
return token && token.type === 'Literal';
|
||||
}
|
||||
function isBracket(token, open) {
|
||||
return token && token.type === 'Bracket' && (open == null || token.open === open);
|
||||
}
|
||||
function isOpenBracket(token) {
|
||||
return isBracket(token, true);
|
||||
}
|
||||
function isCloseBracket(token) {
|
||||
return isBracket(token, false);
|
||||
}
|
||||
function isWhiteSpace(token) {
|
||||
return token && token.type === 'WhiteSpace';
|
||||
}
|
||||
function isOperator(token, operator) {
|
||||
return token && token.type === 'Operator' && (!operator || token.operator === operator);
|
||||
}
|
||||
function isSiblingOperator(token) {
|
||||
return isOperator(token, OperatorType.Sibling);
|
||||
}
|
||||
function isArgumentDelimiter(token) {
|
||||
return isOperator(token, OperatorType.ArgumentDelimiter);
|
||||
}
|
||||
function isFragmentDelimiter(token) {
|
||||
return isArgumentDelimiter(token);
|
||||
}
|
||||
function isImportant(token) {
|
||||
return isOperator(token, OperatorType.Important);
|
||||
}
|
||||
function isValue(token) {
|
||||
return token.type === 'StringValue'
|
||||
|| token.type === 'ColorValue'
|
||||
|| token.type === 'NumberValue'
|
||||
|| token.type === 'Literal'
|
||||
|| token.type === 'Field'
|
||||
|| token.type === 'CustomProperty';
|
||||
}
|
||||
function isValueDelimiter(token) {
|
||||
return isOperator(token, OperatorType.PropertyDelimiter)
|
||||
|| isOperator(token, OperatorType.ValueDelimiter);
|
||||
}
|
||||
function isFunctionStart(scanner) {
|
||||
const t1 = scanner.tokens[scanner.pos];
|
||||
const t2 = scanner.tokens[scanner.pos + 1];
|
||||
return t1 && t2 && isLiteral(t1) && t2.type === 'Bracket';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses given abbreviation into property set
|
||||
*/
|
||||
function parse(abbr, options) {
|
||||
try {
|
||||
const tokens = typeof abbr === 'string' ? tokenize(abbr, options && options.value) : abbr;
|
||||
return parser(tokens, options);
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof ScannerError && typeof abbr === 'string') {
|
||||
err.message += `\n${abbr}\n${'-'.repeat(err.pos)}^`;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export { OperatorType, parse as default, getToken, parser, tokenize };
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@emmetio/css-abbreviation/dist/index.js.map
generated
vendored
Normal file
1
node_modules/@emmetio/css-abbreviation/dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
17
node_modules/@emmetio/css-abbreviation/dist/parser/TokenScanner.d.ts
generated
vendored
Normal file
17
node_modules/@emmetio/css-abbreviation/dist/parser/TokenScanner.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { AllTokens } from '../tokenizer/index.js';
|
||||
export interface TokenScanner {
|
||||
tokens: AllTokens[];
|
||||
start: number;
|
||||
pos: number;
|
||||
size: number;
|
||||
}
|
||||
type TestFn = (token?: AllTokens) => boolean;
|
||||
export default function tokenScanner(tokens: AllTokens[]): TokenScanner;
|
||||
export declare function peek(scanner: TokenScanner): AllTokens | undefined;
|
||||
export declare function next(scanner: TokenScanner): AllTokens | undefined;
|
||||
export declare function slice(scanner: TokenScanner, from?: number, to?: number): AllTokens[];
|
||||
export declare function readable(scanner: TokenScanner): boolean;
|
||||
export declare function consume(scanner: TokenScanner, test: TestFn): boolean;
|
||||
export declare function error(scanner: TokenScanner, message: string, token?: AllTokens | undefined): Error;
|
||||
export declare function consumeWhile(scanner: TokenScanner, test: TestFn): boolean;
|
||||
export {};
|
||||
23
node_modules/@emmetio/css-abbreviation/dist/parser/index.d.ts
generated
vendored
Normal file
23
node_modules/@emmetio/css-abbreviation/dist/parser/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import type { StringValue, NumberValue, ColorValue, Literal, AllTokens, Field, CustomProperty } from '../tokenizer/tokens.js';
|
||||
export type Value = StringValue | NumberValue | ColorValue | Literal | FunctionCall | Field | CustomProperty;
|
||||
export interface FunctionCall {
|
||||
type: 'FunctionCall';
|
||||
name: string;
|
||||
arguments: CSSValue[];
|
||||
}
|
||||
export interface CSSValue {
|
||||
type: 'CSSValue';
|
||||
value: Value[];
|
||||
}
|
||||
export interface CSSProperty {
|
||||
name?: string;
|
||||
value: CSSValue[];
|
||||
important: boolean;
|
||||
/** Snippet matched with current property */
|
||||
snippet?: any;
|
||||
}
|
||||
export interface ParseOptions {
|
||||
/** Consumes given abbreviation tokens as value */
|
||||
value?: boolean;
|
||||
}
|
||||
export default function parser(tokens: AllTokens[], options?: ParseOptions): CSSProperty[];
|
||||
8
node_modules/@emmetio/css-abbreviation/dist/tokenizer/index.d.ts
generated
vendored
Normal file
8
node_modules/@emmetio/css-abbreviation/dist/tokenizer/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { default as Scanner } from '@emmetio/scanner';
|
||||
import type { AllTokens, Literal, NumberValue, ColorValue, WhiteSpace, Operator, Bracket, StringValue, Field, CustomProperty } from './tokens.js';
|
||||
export * from './tokens.js';
|
||||
export default function tokenize(abbr: string, isValue?: boolean): AllTokens[];
|
||||
/**
|
||||
* Returns next token from given scanner, if possible
|
||||
*/
|
||||
export declare function getToken(scanner: Scanner, short?: boolean): Bracket | Literal | Operator | WhiteSpace | ColorValue | NumberValue | StringValue | CustomProperty | Field | undefined;
|
||||
58
node_modules/@emmetio/css-abbreviation/dist/tokenizer/tokens.d.ts
generated
vendored
Normal file
58
node_modules/@emmetio/css-abbreviation/dist/tokenizer/tokens.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
export type AllTokens = Bracket | Literal | Operator | WhiteSpace | ColorValue | NumberValue | StringValue | CustomProperty | Field;
|
||||
export declare const enum OperatorType {
|
||||
Sibling = "+",
|
||||
Important = "!",
|
||||
ArgumentDelimiter = ",",
|
||||
ValueDelimiter = "-",
|
||||
PropertyDelimiter = ":"
|
||||
}
|
||||
export interface Token {
|
||||
type: string;
|
||||
/** Location of token start in source */
|
||||
start?: number;
|
||||
/** Location of token end in source */
|
||||
end?: number;
|
||||
}
|
||||
export interface Operator extends Token {
|
||||
type: 'Operator';
|
||||
operator: OperatorType;
|
||||
}
|
||||
export interface Bracket extends Token {
|
||||
type: 'Bracket';
|
||||
open: boolean;
|
||||
}
|
||||
export interface Literal extends Token {
|
||||
type: 'Literal';
|
||||
value: string;
|
||||
}
|
||||
export interface CustomProperty extends Token {
|
||||
type: 'CustomProperty';
|
||||
value: string;
|
||||
}
|
||||
export interface NumberValue extends Token {
|
||||
type: 'NumberValue';
|
||||
value: number;
|
||||
unit: string;
|
||||
rawValue: string;
|
||||
}
|
||||
export interface ColorValue extends Token {
|
||||
type: 'ColorValue';
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
a: number;
|
||||
raw: string;
|
||||
}
|
||||
export interface StringValue extends Token {
|
||||
type: 'StringValue';
|
||||
value: string;
|
||||
quote: 'single' | 'double';
|
||||
}
|
||||
export interface WhiteSpace extends Token {
|
||||
type: 'WhiteSpace';
|
||||
}
|
||||
export interface Field extends Token {
|
||||
type: 'Field';
|
||||
index?: number;
|
||||
name: string;
|
||||
}
|
||||
40
node_modules/@emmetio/css-abbreviation/dist/tokenizer/utils.d.ts
generated
vendored
Normal file
40
node_modules/@emmetio/css-abbreviation/dist/tokenizer/utils.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
export declare const enum Chars {
|
||||
/** `#` character */
|
||||
Hash = 35,
|
||||
/** `$` character */
|
||||
Dollar = 36,
|
||||
/** `-` character */
|
||||
Dash = 45,
|
||||
/** `.` character */
|
||||
Dot = 46,
|
||||
/** `:` character */
|
||||
Colon = 58,
|
||||
/** `,` character */
|
||||
Comma = 44,
|
||||
/** `!` character */
|
||||
Excl = 33,
|
||||
/** `@` character */
|
||||
At = 64,
|
||||
/** `%` character */
|
||||
Percent = 37,
|
||||
/** `_` character */
|
||||
Underscore = 95,
|
||||
/** `(` character */
|
||||
RoundBracketOpen = 40,
|
||||
/** `)` character */
|
||||
RoundBracketClose = 41,
|
||||
/** `{` character */
|
||||
CurlyBracketOpen = 123,
|
||||
/** `}` character */
|
||||
CurlyBracketClose = 125,
|
||||
/** `+` character */
|
||||
Sibling = 43,
|
||||
/** `'` character */
|
||||
SingleQuote = 39,
|
||||
/** `"` character */
|
||||
DoubleQuote = 34,
|
||||
/** `t` character */
|
||||
Transparent = 116,
|
||||
/** `/` character */
|
||||
Slash = 47
|
||||
}
|
||||
52
node_modules/@emmetio/css-abbreviation/package.json
generated
vendored
Normal file
52
node_modules/@emmetio/css-abbreviation/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "@emmetio/css-abbreviation",
|
||||
"version": "2.1.8",
|
||||
"description": "Parses Emmet CSS abbreviation into AST tree",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"build": "rollup -c",
|
||||
"watch": "rollup -wc",
|
||||
"clean": "rimraf ./dist",
|
||||
"prepublishOnly": "npm run clean && npm run build && npm test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/emmetio/emmet.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Sergey Chikuyonok <serge.che@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/emmetio/emmet/issues"
|
||||
},
|
||||
"homepage": "https://github.com/emmetio/emmet#readme",
|
||||
"dependencies": {
|
||||
"@emmetio/scanner": "^1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/node": "^18.11.18",
|
||||
"mocha": "^10.2.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"rollup": "^3.9.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"mocha": {
|
||||
"loader": "ts-node/esm",
|
||||
"spec": "./test/*.ts"
|
||||
},
|
||||
"gitHead": "fce2127ece65adbb293a40aa0577e4558658c559"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue