astro-ghostcms/.pnpm-store/v3/files/82/4ccbc765a9409fe4e9fe9c92067...

688 lines
20 KiB
Plaintext
Raw Normal View History

2024-02-14 14:10:47 +00:00
'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)) {
// Its a field
index = Number(scanner.current());
name = scanner.eat(Chars.Colon) ? consumePlaceholder(scanner) : '';
}
else if (Scanner.isAlpha(scanner.peek())) {
// Its 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 theres 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)) {
// Its 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 its 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