Spaces:
Configuration error
Configuration error
| import { | |
| Ident, | |
| String as StringToken, | |
| Delim, | |
| LeftSquareBracket, | |
| RightSquareBracket | |
| } from '../../tokenizer/index.js'; | |
| const DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($) | |
| const ASTERISK = 0x002A; // U+002A ASTERISK (*) | |
| const EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=) | |
| const CIRCUMFLEXACCENT = 0x005E; // U+005E (^) | |
| const VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|) | |
| const TILDE = 0x007E; // U+007E TILDE (~) | |
| function getAttributeName() { | |
| if (this.eof) { | |
| this.error('Unexpected end of input'); | |
| } | |
| const start = this.tokenStart; | |
| let expectIdent = false; | |
| if (this.isDelim(ASTERISK)) { | |
| expectIdent = true; | |
| this.next(); | |
| } else if (!this.isDelim(VERTICALLINE)) { | |
| this.eat(Ident); | |
| } | |
| if (this.isDelim(VERTICALLINE)) { | |
| if (this.charCodeAt(this.tokenStart + 1) !== EQUALSSIGN) { | |
| this.next(); | |
| this.eat(Ident); | |
| } else if (expectIdent) { | |
| this.error('Identifier is expected', this.tokenEnd); | |
| } | |
| } else if (expectIdent) { | |
| this.error('Vertical line is expected'); | |
| } | |
| return { | |
| type: 'Identifier', | |
| loc: this.getLocation(start, this.tokenStart), | |
| name: this.substrToCursor(start) | |
| }; | |
| } | |
| function getOperator() { | |
| const start = this.tokenStart; | |
| const code = this.charCodeAt(start); | |
| if (code !== EQUALSSIGN && // = | |
| code !== TILDE && // ~= | |
| code !== CIRCUMFLEXACCENT && // ^= | |
| code !== DOLLARSIGN && // $= | |
| code !== ASTERISK && // *= | |
| code !== VERTICALLINE // |= | |
| ) { | |
| this.error('Attribute selector (=, ~=, ^=, $=, *=, |=) is expected'); | |
| } | |
| this.next(); | |
| if (code !== EQUALSSIGN) { | |
| if (!this.isDelim(EQUALSSIGN)) { | |
| this.error('Equal sign is expected'); | |
| } | |
| this.next(); | |
| } | |
| return this.substrToCursor(start); | |
| } | |
| // '[' <wq-name> ']' | |
| // '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']' | |
| export const name = 'AttributeSelector'; | |
| export const structure = { | |
| name: 'Identifier', | |
| matcher: [String, null], | |
| value: ['String', 'Identifier', null], | |
| flags: [String, null] | |
| }; | |
| export function parse() { | |
| const start = this.tokenStart; | |
| let name; | |
| let matcher = null; | |
| let value = null; | |
| let flags = null; | |
| this.eat(LeftSquareBracket); | |
| this.skipSC(); | |
| name = getAttributeName.call(this); | |
| this.skipSC(); | |
| if (this.tokenType !== RightSquareBracket) { | |
| // avoid case `[name i]` | |
| if (this.tokenType !== Ident) { | |
| matcher = getOperator.call(this); | |
| this.skipSC(); | |
| value = this.tokenType === StringToken | |
| ? this.String() | |
| : this.Identifier(); | |
| this.skipSC(); | |
| } | |
| // attribute flags | |
| if (this.tokenType === Ident) { | |
| flags = this.consume(Ident); | |
| this.skipSC(); | |
| } | |
| } | |
| this.eat(RightSquareBracket); | |
| return { | |
| type: 'AttributeSelector', | |
| loc: this.getLocation(start, this.tokenStart), | |
| name, | |
| matcher, | |
| value, | |
| flags | |
| }; | |
| } | |
| export function generate(node) { | |
| this.token(Delim, '['); | |
| this.node(node.name); | |
| if (node.matcher !== null) { | |
| this.tokenize(node.matcher); | |
| this.node(node.value); | |
| } | |
| if (node.flags !== null) { | |
| this.token(Ident, node.flags); | |
| } | |
| this.token(Delim, ']'); | |
| } | |