🎉 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/abbreviation/LICENSE
generated
vendored
Normal file
21
node_modules/@emmetio/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.
|
||||
76
node_modules/@emmetio/abbreviation/README.md
generated
vendored
Normal file
76
node_modules/@emmetio/abbreviation/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Emmet markup abbreviation parser
|
||||
|
||||
Parses given Emmet *markup* 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.
|
||||
|
||||
Note that AST tree in most cases cannot be used directly for output: for example, AST node produced from `.foo.bar` element misses element name and contains two `class` attributes with `foo` and `bar` values (not a single `class` with `foo bar` value).
|
||||
|
||||
## Usage
|
||||
|
||||
You can install it via npm:
|
||||
|
||||
```bash
|
||||
npm install @emmetio/abbreviation
|
||||
```
|
||||
|
||||
Then add it into your project:
|
||||
|
||||
```js
|
||||
import parse from '@emmetio/abbreviation';
|
||||
|
||||
const tree = parse('div#foo>span.bar*3');
|
||||
/* {
|
||||
type: 'Abbreviation',
|
||||
children: [{
|
||||
type: 'AbbreviationNode',
|
||||
name: 'div',
|
||||
attributes: [...],
|
||||
children: [...]
|
||||
}]
|
||||
} */
|
||||
|
||||
```
|
||||
The returned tree contains `AbbreviationNode` items: a node with name, attributes and/or text content. E.g. an element that can be represented somehow. Repeated and grouped nodes like `a>(b+c)*3` are automatically converted and duplicated as distinct `AbbreviationNode` with distinct `.repeat` property which identifies node in repeating sequence.
|
||||
|
||||
## Abbreviation syntax
|
||||
|
||||
Emmet abbreviation element has the following basic parts:
|
||||
|
||||
```
|
||||
name.class#id[attributes?, ...]{text value}*repeater/
|
||||
```
|
||||
|
||||
* `name` — element name, like `div`, `span` etc. Stored as `node.name` property.
|
||||
* `[attributes]` — list of attributes. Each attribute is stored as [`AbbreviationAttribute`](/src/types.ts) instance and can be accessed by `node.getAttribute(name)`. Each attribute can be written in different formats:
|
||||
* `attr` — attribute with empty value.
|
||||
* `attr=value` — attribute with value. The `value` may contain any character except space or `]`.
|
||||
* `attr="value"` or `attr='value'` — attribute with value in quotes. Quotes are automatically removed. Expression values like `attr={value}` are supported and can be identified by `valueType: "expression"` property.
|
||||
* `attr.` — boolean attribute, e.g. attribute without value, like `required` in `<input>`.
|
||||
* `!attr` – implicit attribute, will be outputted if its value is not empty. Used as a placeholder to preserve attribute order in output.
|
||||
* `./non/attr/value` — value for default attribute. In other words, anything that doesn’t match a attribute name characters. Can be a single- or double-quotted as well. Default attribute is stored with `null` as name and should be used later, for example, to resolve predefined attributes.
|
||||
* `.class` — shorthand for `class` attribute. Note that an element can have multiple classes, like `.class1.class2.class3`.
|
||||
* `#id` — shorthand for `id` attribute.
|
||||
* `{text}` — node’s text content
|
||||
* `*N` — element repeater, tells parser to create `N` copies of given node.
|
||||
* `/` — optional self-closing operator. Marks element with `node.selfClosing = true`.
|
||||
|
||||
### Operators
|
||||
|
||||
Each element of abbreviation must be separated with any of these operators:
|
||||
|
||||
```
|
||||
elem1+elem2>elem3
|
||||
```
|
||||
|
||||
* `+` — sibling operator, adds next element as a next sibling of current element in tree.
|
||||
* `>` — child operator, adds next element as a child of current element.
|
||||
* `^` — climb-up operator, adds next element as a child of current element’s parent node. Multiple climb-up operators are allowed, each operator moves one level up by tree.
|
||||
|
||||
### Groups
|
||||
|
||||
A set of elements could be grouped using `()`, mostly for repeating and for easier elements nesting:
|
||||
|
||||
```
|
||||
a>(b>c+d)*4+(e+f)
|
||||
```
|
||||
|
||||
Groups can be optionally concatenated with `+` operator.
|
||||
8
node_modules/@emmetio/abbreviation/dist/convert.d.ts
generated
vendored
Normal file
8
node_modules/@emmetio/abbreviation/dist/convert.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { TokenGroup } from './parser/index.js';
|
||||
import { Abbreviation, ParserOptions } from './types.js';
|
||||
/**
|
||||
* Converts given token-based abbreviation into simplified and unrolled node-based
|
||||
* abbreviation
|
||||
*/
|
||||
export default function convert(abbr: TokenGroup, options?: ParserOptions): Abbreviation;
|
||||
export declare function isGroup(node: any): node is TokenGroup;
|
||||
1245
node_modules/@emmetio/abbreviation/dist/index.cjs
generated
vendored
Normal file
1245
node_modules/@emmetio/abbreviation/dist/index.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
node_modules/@emmetio/abbreviation/dist/index.cjs.map
generated
vendored
Normal file
1
node_modules/@emmetio/abbreviation/dist/index.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
12
node_modules/@emmetio/abbreviation/dist/index.d.ts
generated
vendored
Normal file
12
node_modules/@emmetio/abbreviation/dist/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import parse, { type TokenGroup } from './parser/index.js';
|
||||
import tokenize, { getToken, type AllTokens } from './tokenizer/index.js';
|
||||
import convert from './convert.js';
|
||||
import type { ParserOptions } from './types.js';
|
||||
export { parse, tokenize, getToken, convert };
|
||||
export * from './tokenizer/tokens.js';
|
||||
export * from './types.js';
|
||||
export type MarkupAbbreviation = TokenGroup;
|
||||
/**
|
||||
* Parses given abbreviation into node tree
|
||||
*/
|
||||
export default function parseAbbreviation(abbr: string | AllTokens[], options?: ParserOptions): import("./types.js").Abbreviation;
|
||||
1237
node_modules/@emmetio/abbreviation/dist/index.js
generated
vendored
Normal file
1237
node_modules/@emmetio/abbreviation/dist/index.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
node_modules/@emmetio/abbreviation/dist/index.js.map
generated
vendored
Normal file
1
node_modules/@emmetio/abbreviation/dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
17
node_modules/@emmetio/abbreviation/dist/parser/TokenScanner.d.ts
generated
vendored
Normal file
17
node_modules/@emmetio/abbreviation/dist/parser/TokenScanner.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { 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 {};
|
||||
31
node_modules/@emmetio/abbreviation/dist/parser/index.d.ts
generated
vendored
Normal file
31
node_modules/@emmetio/abbreviation/dist/parser/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import type { NameToken, ValueToken, Repeater, AllTokens, BracketType, Bracket, Operator, OperatorType, Quote } from '../tokenizer/index.js';
|
||||
import type { ParserOptions } from '../types.js';
|
||||
export type TokenStatement = TokenElement | TokenGroup;
|
||||
export interface TokenAttribute {
|
||||
name?: ValueToken[];
|
||||
value?: ValueToken[];
|
||||
expression?: boolean;
|
||||
/**
|
||||
* Indicates that current attribute was repeated multiple times in a row.
|
||||
* Used to alter output of multiple shorthand attributes like `..` (double class)
|
||||
*/
|
||||
multiple?: boolean;
|
||||
}
|
||||
export interface TokenElement {
|
||||
type: 'TokenElement';
|
||||
name?: NameToken[];
|
||||
attributes?: TokenAttribute[];
|
||||
value?: ValueToken[];
|
||||
repeat?: Repeater;
|
||||
selfClose: boolean;
|
||||
elements: TokenStatement[];
|
||||
}
|
||||
export interface TokenGroup {
|
||||
type: 'TokenGroup';
|
||||
elements: TokenStatement[];
|
||||
repeat?: Repeater;
|
||||
}
|
||||
export default function abbreviation(abbr: AllTokens[], options?: ParserOptions): TokenGroup;
|
||||
export declare function isBracket(token: AllTokens | undefined, context?: BracketType, isOpen?: boolean): token is Bracket;
|
||||
export declare function isOperator(token: AllTokens | undefined, type?: OperatorType): token is Operator;
|
||||
export declare function isQuote(token: AllTokens | undefined, isSingle?: boolean): token is Quote;
|
||||
6
node_modules/@emmetio/abbreviation/dist/stringify.d.ts
generated
vendored
Normal file
6
node_modules/@emmetio/abbreviation/dist/stringify.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { ValueToken } from './tokenizer/tokens.js';
|
||||
import { ConvertState } from './types.js';
|
||||
/**
|
||||
* Converts given value token to string
|
||||
*/
|
||||
export default function stringify(token: ValueToken, state: ConvertState): string;
|
||||
13
node_modules/@emmetio/abbreviation/dist/tokenizer/index.d.ts
generated
vendored
Normal file
13
node_modules/@emmetio/abbreviation/dist/tokenizer/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import Scanner from '@emmetio/scanner';
|
||||
import type { BracketType, AllTokens } from './tokens.js';
|
||||
export * from './tokens.js';
|
||||
type Context = {
|
||||
[ctx in BracketType]: number;
|
||||
} & {
|
||||
quote: number;
|
||||
};
|
||||
export default function tokenize(source: string): AllTokens[];
|
||||
/**
|
||||
* Returns next token from given scanner, if possible
|
||||
*/
|
||||
export declare function getToken(scanner: Scanner, ctx: Context): AllTokens | undefined;
|
||||
63
node_modules/@emmetio/abbreviation/dist/tokenizer/tokens.d.ts
generated
vendored
Normal file
63
node_modules/@emmetio/abbreviation/dist/tokenizer/tokens.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
export type OperatorType = 'child' | 'sibling' | 'climb' | 'class' | 'id' | 'close' | 'equal';
|
||||
export type BracketType = 'group' | 'attribute' | 'expression';
|
||||
export type AllTokens = Bracket | Field | Literal | Operator | Quote | Repeater | RepeaterNumber | RepeaterPlaceholder | WhiteSpace;
|
||||
export type NameToken = Literal | RepeaterNumber;
|
||||
export type ValueToken = Literal | Quote | Bracket | Field | RepeaterPlaceholder | RepeaterNumber;
|
||||
export interface Token {
|
||||
type: string;
|
||||
/** Location of token start in source */
|
||||
start?: number;
|
||||
/** Location of token end in source */
|
||||
end?: number;
|
||||
}
|
||||
export interface Repeater extends Token {
|
||||
type: 'Repeater';
|
||||
/** How many times context element should be repeated */
|
||||
count: number;
|
||||
/** Position of context element in its repeating sequence */
|
||||
value: number;
|
||||
/** Repeater is implicit, e.g. repeated by the amount of text lines selected by user */
|
||||
implicit: boolean;
|
||||
}
|
||||
export interface RepeaterNumber extends Token {
|
||||
type: 'RepeaterNumber';
|
||||
/** Size of repeater content, e.g. the amount consequent numbering characters */
|
||||
size: number;
|
||||
/** Should output numbering in reverse order? */
|
||||
reverse: boolean;
|
||||
/** Base value to start numbering from */
|
||||
base: number;
|
||||
/** Parent offset from which numbering should be used */
|
||||
parent: number;
|
||||
}
|
||||
export interface RepeaterPlaceholder extends Token {
|
||||
type: 'RepeaterPlaceholder';
|
||||
/** Value to insert instead of placeholder */
|
||||
value?: string;
|
||||
}
|
||||
export interface Field extends Token {
|
||||
type: 'Field';
|
||||
index?: number;
|
||||
name: string;
|
||||
}
|
||||
export interface Operator extends Token {
|
||||
type: 'Operator';
|
||||
operator: OperatorType;
|
||||
}
|
||||
export interface Bracket extends Token {
|
||||
type: 'Bracket';
|
||||
open: boolean;
|
||||
context: BracketType;
|
||||
}
|
||||
export interface Quote extends Token {
|
||||
type: 'Quote';
|
||||
single: boolean;
|
||||
}
|
||||
export interface Literal extends Token {
|
||||
type: 'Literal';
|
||||
value: string;
|
||||
}
|
||||
export interface WhiteSpace extends Token {
|
||||
type: 'WhiteSpace';
|
||||
value: string;
|
||||
}
|
||||
53
node_modules/@emmetio/abbreviation/dist/tokenizer/utils.d.ts
generated
vendored
Normal file
53
node_modules/@emmetio/abbreviation/dist/tokenizer/utils.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import type Scanner from '@emmetio/scanner';
|
||||
export declare const enum Chars {
|
||||
/** `{` character */
|
||||
CurlyBracketOpen = 123,
|
||||
/** `}` character */
|
||||
CurlyBracketClose = 125,
|
||||
/** `\\` character */
|
||||
Escape = 92,
|
||||
/** `=` character */
|
||||
Equals = 61,
|
||||
/** `[` character */
|
||||
SquareBracketOpen = 91,
|
||||
/** `]` character */
|
||||
SquareBracketClose = 93,
|
||||
/** `*` character */
|
||||
Asterisk = 42,
|
||||
/** `#` character */
|
||||
Hash = 35,
|
||||
/** `$` character */
|
||||
Dollar = 36,
|
||||
/** `-` character */
|
||||
Dash = 45,
|
||||
/** `.` character */
|
||||
Dot = 46,
|
||||
/** `/` character */
|
||||
Slash = 47,
|
||||
/** `:` character */
|
||||
Colon = 58,
|
||||
/** `!` character */
|
||||
Excl = 33,
|
||||
/** `@` character */
|
||||
At = 64,
|
||||
/** `_` character */
|
||||
Underscore = 95,
|
||||
/** `(` character */
|
||||
RoundBracketOpen = 40,
|
||||
/** `)` character */
|
||||
RoundBracketClose = 41,
|
||||
/** `+` character */
|
||||
Sibling = 43,
|
||||
/** `>` character */
|
||||
Child = 62,
|
||||
/** `^` character */
|
||||
Climb = 94,
|
||||
/** `'` character */
|
||||
SingleQuote = 39,
|
||||
/** `""` character */
|
||||
DoubleQuote = 34
|
||||
}
|
||||
/**
|
||||
* If consumes escape character, sets current stream range to escaped value
|
||||
*/
|
||||
export declare function escaped(scanner: Scanner): boolean;
|
||||
56
node_modules/@emmetio/abbreviation/dist/types.d.ts
generated
vendored
Normal file
56
node_modules/@emmetio/abbreviation/dist/types.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { Field, Repeater } from './tokenizer/index.js';
|
||||
export interface ParserOptions {
|
||||
/** Text strings to insert into implicitly repeated elements */
|
||||
text?: string | string[];
|
||||
/** Variable values for `${var}` tokens */
|
||||
variables?: {
|
||||
[name: string]: string;
|
||||
};
|
||||
/** Max amount of repeated elements in abbreviation */
|
||||
maxRepeat?: number;
|
||||
/** Enabled JSX parsing mode */
|
||||
jsx?: boolean;
|
||||
/** Enable inserting text into href attribute of links */
|
||||
href?: boolean;
|
||||
}
|
||||
export interface ConvertState {
|
||||
inserted: boolean;
|
||||
text?: string | string[];
|
||||
cleanText?: string | string[];
|
||||
repeatGuard: number;
|
||||
/** Context repeaters, e.g. all actual repeaters from parent */
|
||||
repeaters: Repeater[];
|
||||
getText(pos?: number): string;
|
||||
getVariable(name: string): string;
|
||||
}
|
||||
export type Value = string | Field;
|
||||
export type AttributeType = 'raw' | 'singleQuote' | 'doubleQuote' | 'expression';
|
||||
export interface Abbreviation {
|
||||
type: 'Abbreviation';
|
||||
children: AbbreviationNode[];
|
||||
}
|
||||
export interface AbbreviationNode {
|
||||
type: 'AbbreviationNode';
|
||||
name?: string;
|
||||
value?: Value[];
|
||||
repeat?: Repeater;
|
||||
attributes?: AbbreviationAttribute[];
|
||||
children: AbbreviationNode[];
|
||||
/** Indicates current element is self-closing, e.g. should not contain closing pair */
|
||||
selfClosing?: boolean;
|
||||
}
|
||||
export interface AbbreviationAttribute {
|
||||
name?: string;
|
||||
value?: Value[];
|
||||
/** Indicates type of value stored in `.value` property */
|
||||
valueType: AttributeType;
|
||||
/** Attribute is boolean (e.g.name equals value) */
|
||||
boolean?: boolean;
|
||||
/** Attribute is implied (e.g.must be outputted only if contains non-null value) */
|
||||
implied?: boolean;
|
||||
/**
|
||||
* Internal property that indicates that given attribute was specified
|
||||
* more than once as a shorthand. E.g. `..` is a multiple `class` attribute
|
||||
*/
|
||||
multiple?: boolean;
|
||||
}
|
||||
54
node_modules/@emmetio/abbreviation/package.json
generated
vendored
Normal file
54
node_modules/@emmetio/abbreviation/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"name": "@emmetio/abbreviation",
|
||||
"version": "2.3.3",
|
||||
"description": "Emmet standalone abbreviation parser",
|
||||
"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",
|
||||
"clean": "rimraf ./dist",
|
||||
"prepublishOnly": "npm run clean && npm run build && npm test"
|
||||
},
|
||||
"keywords": [
|
||||
"emmet",
|
||||
"abbreviation"
|
||||
],
|
||||
"author": "Sergey Chikuyonok <serge.che@gmail.com>",
|
||||
"license": "MIT",
|
||||
"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"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/emmetio/emmet.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/emmetio/emmet/issues"
|
||||
},
|
||||
"homepage": "https://github.com/emmetio/emmet#readme",
|
||||
"mocha": {
|
||||
"loader": "ts-node/esm",
|
||||
"spec": "./test/*.ts"
|
||||
},
|
||||
"gitHead": "fce2127ece65adbb293a40aa0577e4558658c559"
|
||||
}
|
||||
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"
|
||||
}
|
||||
21
node_modules/@emmetio/scanner/LICENSE
generated
vendored
Normal file
21
node_modules/@emmetio/scanner/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.
|
||||
49
node_modules/@emmetio/scanner/package.json
generated
vendored
Normal file
49
node_modules/@emmetio/scanner/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "@emmetio/scanner",
|
||||
"version": "1.0.4",
|
||||
"description": "Scans given text character-by-character",
|
||||
"main": "./scanner.cjs",
|
||||
"module": "./scanner.js",
|
||||
"types": "./scanner.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"import": "./scanner.js",
|
||||
"require": "./scanner.cjs"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"build": "rollup -c",
|
||||
"clean": "rimraf ./scanner.* ./*.d.ts",
|
||||
"prepublishOnly": "npm run clean && npm run build && npm test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/emmetio/stream-reader.git"
|
||||
},
|
||||
"keywords": [
|
||||
"emmet",
|
||||
"stream",
|
||||
"scanner"
|
||||
],
|
||||
"author": "Sergey Chikuyonok <serge.che@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/emmetio/emmet/issues"
|
||||
},
|
||||
"homepage": "https://github.com/emmetio/emmet#readme",
|
||||
"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"
|
||||
},
|
||||
"mocha": {
|
||||
"loader": "ts-node/esm",
|
||||
"spec": "./test/*.ts"
|
||||
},
|
||||
"gitHead": "fce2127ece65adbb293a40aa0577e4558658c559"
|
||||
}
|
||||
253
node_modules/@emmetio/scanner/scanner.cjs
generated
vendored
Normal file
253
node_modules/@emmetio/scanner/scanner.cjs
generated
vendored
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
const defaultQuotedOptions = {
|
||||
escape: 92,
|
||||
throws: false
|
||||
};
|
||||
/**
|
||||
* Check if given code is a number
|
||||
*/
|
||||
function isNumber(code) {
|
||||
return code > 47 && code < 58;
|
||||
}
|
||||
/**
|
||||
* Check if given character code is alpha code (letter through A to Z)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
function isAlphaNumeric(code) {
|
||||
return isNumber(code) || isAlpha(code);
|
||||
}
|
||||
function isAlphaNumericWord(code) {
|
||||
return isNumber(code) || isAlphaWord(code);
|
||||
}
|
||||
function isAlphaWord(code) {
|
||||
return code === 95 /* _ */ || isAlpha(code);
|
||||
}
|
||||
/**
|
||||
* Check for Umlauts i.e. ä, Ä, ö, Ö, ü and Ü
|
||||
*/
|
||||
function isUmlaut(code) {
|
||||
return code === 196
|
||||
|| code == 214
|
||||
|| code === 220
|
||||
|| code === 228
|
||||
|| code === 246
|
||||
|| code === 252;
|
||||
}
|
||||
/**
|
||||
* Check if given character code is a white-space character: a space character
|
||||
* or line breaks
|
||||
*/
|
||||
function isWhiteSpace(code) {
|
||||
return code === 32 /* space */
|
||||
|| code === 9 /* tab */
|
||||
|| code === 160; /* non-breaking space */
|
||||
}
|
||||
/**
|
||||
* Check if given character code is a space character
|
||||
*/
|
||||
function isSpace(code) {
|
||||
return isWhiteSpace(code)
|
||||
|| code === 10 /* LF */
|
||||
|| code === 13; /* CR */
|
||||
}
|
||||
/**
|
||||
* Consumes 'single' or "double"-quoted string from given string, if possible
|
||||
* @return `true` if quoted string was consumed. The contents of quoted string
|
||||
* will be available as `stream.current()`
|
||||
*/
|
||||
function eatQuoted(stream, options) {
|
||||
options = Object.assign(Object.assign({}, defaultQuotedOptions), options);
|
||||
const start = stream.pos;
|
||||
const quote = stream.peek();
|
||||
if (stream.eat(isQuote)) {
|
||||
while (!stream.eof()) {
|
||||
switch (stream.next()) {
|
||||
case quote:
|
||||
stream.start = start;
|
||||
return true;
|
||||
case options.escape:
|
||||
stream.next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we’re here then stream wasn’t properly consumed.
|
||||
// Revert stream and decide what to do
|
||||
stream.pos = start;
|
||||
if (options.throws) {
|
||||
throw stream.error('Unable to consume quoted string');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Check if given character code is a quote character
|
||||
*/
|
||||
function isQuote(code) {
|
||||
return code === 39 /* ' */ || code === 34 /* " */;
|
||||
}
|
||||
/**
|
||||
* Eats paired characters substring, for example `(foo)` or `[bar]`
|
||||
* @param open Character code of pair opening
|
||||
* @param close Character code of pair closing
|
||||
* @return Returns `true` if character pair was successfully consumed, it’s
|
||||
* content will be available as `stream.current()`
|
||||
*/
|
||||
function eatPair(stream, open, close, options) {
|
||||
options = Object.assign(Object.assign({}, defaultQuotedOptions), options);
|
||||
const start = stream.pos;
|
||||
if (stream.eat(open)) {
|
||||
let stack = 1;
|
||||
let ch;
|
||||
while (!stream.eof()) {
|
||||
if (eatQuoted(stream, options)) {
|
||||
continue;
|
||||
}
|
||||
ch = stream.next();
|
||||
if (ch === open) {
|
||||
stack++;
|
||||
}
|
||||
else if (ch === close) {
|
||||
stack--;
|
||||
if (!stack) {
|
||||
stream.start = start;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ch === options.escape) {
|
||||
stream.next();
|
||||
}
|
||||
}
|
||||
// If we’re here then paired character can’t be consumed
|
||||
stream.pos = start;
|
||||
if (options.throws) {
|
||||
throw stream.error(`Unable to find matching pair for ${String.fromCharCode(open)}`);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A streaming, character code-based string reader
|
||||
*/
|
||||
class Scanner {
|
||||
constructor(str, start, end) {
|
||||
if (end == null && typeof str === 'string') {
|
||||
end = str.length;
|
||||
}
|
||||
this.string = str;
|
||||
this.pos = this.start = start || 0;
|
||||
this.end = end || 0;
|
||||
}
|
||||
/**
|
||||
* Returns true only if the stream is at the end of the file.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
limit(start, end) {
|
||||
return new Scanner(this.string, start, end);
|
||||
}
|
||||
/**
|
||||
* Returns the next character code in the stream without advancing it.
|
||||
* Will return NaN at the end of the file.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
backUp(n) {
|
||||
this.pos -= (n || 1);
|
||||
}
|
||||
/**
|
||||
* Get the string between the start of the current token and the
|
||||
* current stream position.
|
||||
*/
|
||||
current() {
|
||||
return this.substring(this.start, this.pos);
|
||||
}
|
||||
/**
|
||||
* Returns substring for given range
|
||||
*/
|
||||
substring(start, end) {
|
||||
return this.string.slice(start, end);
|
||||
}
|
||||
/**
|
||||
* Creates error object with current stream state
|
||||
*/
|
||||
error(message, pos = this.pos) {
|
||||
return new ScannerError(`${message} at ${pos + 1}`, pos, this.string);
|
||||
}
|
||||
}
|
||||
class ScannerError extends Error {
|
||||
constructor(message, pos, str) {
|
||||
super(message);
|
||||
this.pos = pos;
|
||||
this.string = str;
|
||||
}
|
||||
}
|
||||
|
||||
exports.ScannerError = ScannerError;
|
||||
exports.default = Scanner;
|
||||
exports.eatPair = eatPair;
|
||||
exports.eatQuoted = eatQuoted;
|
||||
exports.isAlpha = isAlpha;
|
||||
exports.isAlphaNumeric = isAlphaNumeric;
|
||||
exports.isAlphaNumericWord = isAlphaNumericWord;
|
||||
exports.isAlphaWord = isAlphaWord;
|
||||
exports.isNumber = isNumber;
|
||||
exports.isQuote = isQuote;
|
||||
exports.isSpace = isSpace;
|
||||
exports.isUmlaut = isUmlaut;
|
||||
exports.isWhiteSpace = isWhiteSpace;
|
||||
//# sourceMappingURL=scanner.cjs.map
|
||||
1
node_modules/@emmetio/scanner/scanner.cjs.map
generated
vendored
Normal file
1
node_modules/@emmetio/scanner/scanner.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
71
node_modules/@emmetio/scanner/scanner.d.ts
generated
vendored
Normal file
71
node_modules/@emmetio/scanner/scanner.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
export * from './utils.js';
|
||||
type MatchFn = (ch: number) => boolean;
|
||||
/**
|
||||
* A streaming, character code-based string reader
|
||||
*/
|
||||
export default class Scanner {
|
||||
/** Current string */
|
||||
string: string;
|
||||
/** Current scanner position */
|
||||
pos: number;
|
||||
/** Lower range limit where string reader is available */
|
||||
start: number;
|
||||
/** Upper range limit where string reader is available */
|
||||
end: number;
|
||||
constructor(str: string, start?: number, end?: number);
|
||||
/**
|
||||
* Returns true only if the stream is at the end of the file.
|
||||
*/
|
||||
eof(): boolean;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
limit(start?: number, end?: number): Scanner;
|
||||
/**
|
||||
* Returns the next character code in the stream without advancing it.
|
||||
* Will return NaN at the end of the file.
|
||||
*/
|
||||
peek(): number;
|
||||
/**
|
||||
* Returns the next character in the stream and advances it.
|
||||
* Also returns <code>undefined</code> when no more characters are available.
|
||||
*/
|
||||
next(): number | undefined;
|
||||
/**
|
||||
* `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.
|
||||
*/
|
||||
eat(match: number | MatchFn): boolean;
|
||||
/**
|
||||
* Repeatedly calls <code>eat</code> with the given argument, until it
|
||||
* fails. Returns <code>true</code> if any characters were eaten.
|
||||
*/
|
||||
eatWhile(match: number | MatchFn): boolean;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
backUp(n: number): void;
|
||||
/**
|
||||
* Get the string between the start of the current token and the
|
||||
* current stream position.
|
||||
*/
|
||||
current(): string;
|
||||
/**
|
||||
* Returns substring for given range
|
||||
*/
|
||||
substring(start: number, end?: number): string;
|
||||
/**
|
||||
* Creates error object with current stream state
|
||||
*/
|
||||
error(message: string, pos?: number): ScannerError;
|
||||
}
|
||||
export declare class ScannerError extends Error {
|
||||
pos: number;
|
||||
string: string;
|
||||
constructor(message: string, pos: number, str: string);
|
||||
}
|
||||
237
node_modules/@emmetio/scanner/scanner.js
generated
vendored
Normal file
237
node_modules/@emmetio/scanner/scanner.js
generated
vendored
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
const defaultQuotedOptions = {
|
||||
escape: 92,
|
||||
throws: false
|
||||
};
|
||||
/**
|
||||
* Check if given code is a number
|
||||
*/
|
||||
function isNumber(code) {
|
||||
return code > 47 && code < 58;
|
||||
}
|
||||
/**
|
||||
* Check if given character code is alpha code (letter through A to Z)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
function isAlphaNumeric(code) {
|
||||
return isNumber(code) || isAlpha(code);
|
||||
}
|
||||
function isAlphaNumericWord(code) {
|
||||
return isNumber(code) || isAlphaWord(code);
|
||||
}
|
||||
function isAlphaWord(code) {
|
||||
return code === 95 /* _ */ || isAlpha(code);
|
||||
}
|
||||
/**
|
||||
* Check for Umlauts i.e. ä, Ä, ö, Ö, ü and Ü
|
||||
*/
|
||||
function isUmlaut(code) {
|
||||
return code === 196
|
||||
|| code == 214
|
||||
|| code === 220
|
||||
|| code === 228
|
||||
|| code === 246
|
||||
|| code === 252;
|
||||
}
|
||||
/**
|
||||
* Check if given character code is a white-space character: a space character
|
||||
* or line breaks
|
||||
*/
|
||||
function isWhiteSpace(code) {
|
||||
return code === 32 /* space */
|
||||
|| code === 9 /* tab */
|
||||
|| code === 160; /* non-breaking space */
|
||||
}
|
||||
/**
|
||||
* Check if given character code is a space character
|
||||
*/
|
||||
function isSpace(code) {
|
||||
return isWhiteSpace(code)
|
||||
|| code === 10 /* LF */
|
||||
|| code === 13; /* CR */
|
||||
}
|
||||
/**
|
||||
* Consumes 'single' or "double"-quoted string from given string, if possible
|
||||
* @return `true` if quoted string was consumed. The contents of quoted string
|
||||
* will be available as `stream.current()`
|
||||
*/
|
||||
function eatQuoted(stream, options) {
|
||||
options = Object.assign(Object.assign({}, defaultQuotedOptions), options);
|
||||
const start = stream.pos;
|
||||
const quote = stream.peek();
|
||||
if (stream.eat(isQuote)) {
|
||||
while (!stream.eof()) {
|
||||
switch (stream.next()) {
|
||||
case quote:
|
||||
stream.start = start;
|
||||
return true;
|
||||
case options.escape:
|
||||
stream.next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we’re here then stream wasn’t properly consumed.
|
||||
// Revert stream and decide what to do
|
||||
stream.pos = start;
|
||||
if (options.throws) {
|
||||
throw stream.error('Unable to consume quoted string');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Check if given character code is a quote character
|
||||
*/
|
||||
function isQuote(code) {
|
||||
return code === 39 /* ' */ || code === 34 /* " */;
|
||||
}
|
||||
/**
|
||||
* Eats paired characters substring, for example `(foo)` or `[bar]`
|
||||
* @param open Character code of pair opening
|
||||
* @param close Character code of pair closing
|
||||
* @return Returns `true` if character pair was successfully consumed, it’s
|
||||
* content will be available as `stream.current()`
|
||||
*/
|
||||
function eatPair(stream, open, close, options) {
|
||||
options = Object.assign(Object.assign({}, defaultQuotedOptions), options);
|
||||
const start = stream.pos;
|
||||
if (stream.eat(open)) {
|
||||
let stack = 1;
|
||||
let ch;
|
||||
while (!stream.eof()) {
|
||||
if (eatQuoted(stream, options)) {
|
||||
continue;
|
||||
}
|
||||
ch = stream.next();
|
||||
if (ch === open) {
|
||||
stack++;
|
||||
}
|
||||
else if (ch === close) {
|
||||
stack--;
|
||||
if (!stack) {
|
||||
stream.start = start;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ch === options.escape) {
|
||||
stream.next();
|
||||
}
|
||||
}
|
||||
// If we’re here then paired character can’t be consumed
|
||||
stream.pos = start;
|
||||
if (options.throws) {
|
||||
throw stream.error(`Unable to find matching pair for ${String.fromCharCode(open)}`);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A streaming, character code-based string reader
|
||||
*/
|
||||
class Scanner {
|
||||
constructor(str, start, end) {
|
||||
if (end == null && typeof str === 'string') {
|
||||
end = str.length;
|
||||
}
|
||||
this.string = str;
|
||||
this.pos = this.start = start || 0;
|
||||
this.end = end || 0;
|
||||
}
|
||||
/**
|
||||
* Returns true only if the stream is at the end of the file.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
limit(start, end) {
|
||||
return new Scanner(this.string, start, end);
|
||||
}
|
||||
/**
|
||||
* Returns the next character code in the stream without advancing it.
|
||||
* Will return NaN at the end of the file.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
backUp(n) {
|
||||
this.pos -= (n || 1);
|
||||
}
|
||||
/**
|
||||
* Get the string between the start of the current token and the
|
||||
* current stream position.
|
||||
*/
|
||||
current() {
|
||||
return this.substring(this.start, this.pos);
|
||||
}
|
||||
/**
|
||||
* Returns substring for given range
|
||||
*/
|
||||
substring(start, end) {
|
||||
return this.string.slice(start, end);
|
||||
}
|
||||
/**
|
||||
* Creates error object with current stream state
|
||||
*/
|
||||
error(message, pos = this.pos) {
|
||||
return new ScannerError(`${message} at ${pos + 1}`, pos, this.string);
|
||||
}
|
||||
}
|
||||
class ScannerError extends Error {
|
||||
constructor(message, pos, str) {
|
||||
super(message);
|
||||
this.pos = pos;
|
||||
this.string = str;
|
||||
}
|
||||
}
|
||||
|
||||
export { ScannerError, Scanner as default, eatPair, eatQuoted, isAlpha, isAlphaNumeric, isAlphaNumericWord, isAlphaWord, isNumber, isQuote, isSpace, isUmlaut, isWhiteSpace };
|
||||
//# sourceMappingURL=scanner.js.map
|
||||
1
node_modules/@emmetio/scanner/scanner.js.map
generated
vendored
Normal file
1
node_modules/@emmetio/scanner/scanner.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
53
node_modules/@emmetio/scanner/utils.d.ts
generated
vendored
Normal file
53
node_modules/@emmetio/scanner/utils.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import type Scanner from './scanner.js';
|
||||
interface QuotedOptions {
|
||||
/** A character code of quote-escape symbol */
|
||||
escape?: number;
|
||||
/** Throw error if quotes string can’t be properly consumed */
|
||||
throws?: boolean;
|
||||
}
|
||||
/**
|
||||
* Check if given code is a number
|
||||
*/
|
||||
export declare function isNumber(code: number): boolean;
|
||||
/**
|
||||
* Check if given character code is alpha code (letter through A to Z)
|
||||
*/
|
||||
export declare function isAlpha(code: number, from?: number, to?: number): boolean;
|
||||
/**
|
||||
* Check if given character code is alpha-numeric (letter through A to Z or number)
|
||||
*/
|
||||
export declare function isAlphaNumeric(code: number): boolean;
|
||||
export declare function isAlphaNumericWord(code: number): boolean;
|
||||
export declare function isAlphaWord(code: number): boolean;
|
||||
/**
|
||||
* Check for Umlauts i.e. ä, Ä, ö, Ö, ü and Ü
|
||||
*/
|
||||
export declare function isUmlaut(code: number): boolean;
|
||||
/**
|
||||
* Check if given character code is a white-space character: a space character
|
||||
* or line breaks
|
||||
*/
|
||||
export declare function isWhiteSpace(code: number): boolean;
|
||||
/**
|
||||
* Check if given character code is a space character
|
||||
*/
|
||||
export declare function isSpace(code: number): boolean;
|
||||
/**
|
||||
* Consumes 'single' or "double"-quoted string from given string, if possible
|
||||
* @return `true` if quoted string was consumed. The contents of quoted string
|
||||
* will be available as `stream.current()`
|
||||
*/
|
||||
export declare function eatQuoted(stream: Scanner, options?: QuotedOptions): boolean;
|
||||
/**
|
||||
* Check if given character code is a quote character
|
||||
*/
|
||||
export declare function isQuote(code: number): boolean;
|
||||
/**
|
||||
* Eats paired characters substring, for example `(foo)` or `[bar]`
|
||||
* @param open Character code of pair opening
|
||||
* @param close Character code of pair closing
|
||||
* @return Returns `true` if character pair was successfully consumed, it’s
|
||||
* content will be available as `stream.current()`
|
||||
*/
|
||||
export declare function eatPair(stream: Scanner, open: number, close: number, options?: QuotedOptions): boolean;
|
||||
export {};
|
||||
Loading…
Add table
Add a link
Reference in a new issue