diff options
Diffstat (limited to 'src/parser/parse/read')
-rw-r--r-- | src/parser/parse/read/context.ts | 72 | ||||
-rw-r--r-- | src/parser/parse/read/expression.ts | 251 | ||||
-rw-r--r-- | src/parser/parse/read/script.ts | 60 | ||||
-rw-r--r-- | src/parser/parse/read/style.ts | 40 |
4 files changed, 0 insertions, 423 deletions
diff --git a/src/parser/parse/read/context.ts b/src/parser/parse/read/context.ts deleted file mode 100644 index 565c66d18..000000000 --- a/src/parser/parse/read/context.ts +++ /dev/null @@ -1,72 +0,0 @@ -// @ts-nocheck - -import { Parser } from '../index.js'; -import { isIdentifierStart } from 'acorn'; -import full_char_code_at from '../../utils/full_char_code_at.js'; -import { is_bracket_open, is_bracket_close, is_bracket_pair, get_bracket_close } from '../utils/bracket.js'; -import { parse_expression_at } from './expression.js'; -import { Pattern } from 'estree'; - -export default function read_context(parser: Parser): Pattern & { start: number; end: number } { - const start = parser.index; - let i = parser.index; - - const code = full_char_code_at(parser.template, i); - if (isIdentifierStart(code, true)) { - return { - type: 'Identifier', - name: parser.read_identifier(), - start, - end: parser.index, - }; - } - - if (!is_bracket_open(code)) { - parser.error({ - code: 'unexpected-token', - message: 'Expected identifier or destructure pattern', - }); - } - - const bracket_stack = [code]; - i += code <= 0xffff ? 1 : 2; - - while (i < parser.template.length) { - const code = full_char_code_at(parser.template, i); - if (is_bracket_open(code)) { - bracket_stack.push(code); - } else if (is_bracket_close(code)) { - if (!is_bracket_pair(bracket_stack[bracket_stack.length - 1], code)) { - parser.error({ - code: 'unexpected-token', - message: `Expected ${String.fromCharCode(get_bracket_close(bracket_stack[bracket_stack.length - 1]))}`, - }); - } - bracket_stack.pop(); - if (bracket_stack.length === 0) { - i += code <= 0xffff ? 1 : 2; - break; - } - } - i += code <= 0xffff ? 1 : 2; - } - - parser.index = i; - - const pattern_string = parser.template.slice(start, i); - try { - // the length of the `space_with_newline` has to be start - 1 - // because we added a `(` in front of the pattern_string, - // which shifted the entire string to right by 1 - // so we offset it by removing 1 character in the `space_with_newline` - // to achieve that, we remove the 1st space encountered, - // so it will not affect the `column` of the node - let space_with_newline = parser.template.slice(0, start).replace(/[^\n]/g, ' '); - const first_space = space_with_newline.indexOf(' '); - space_with_newline = space_with_newline.slice(0, first_space) + space_with_newline.slice(first_space + 1); - - return (parse_expression_at(`${space_with_newline}(${pattern_string} = 1)`, start - 1) as any).left; - } catch (error) { - parser.acorn_error(error); - } -} diff --git a/src/parser/parse/read/expression.ts b/src/parser/parse/read/expression.ts deleted file mode 100644 index 9d0d09175..000000000 --- a/src/parser/parse/read/expression.ts +++ /dev/null @@ -1,251 +0,0 @@ -import type { BaseNode, Expression } from '../../interfaces'; -import { Parser } from '../index.js'; -import parseAstro from '../index.js'; - -interface ParseState { - source: string; - start: number; - index: number; - curlyCount: number; - bracketCount: number; - root: Expression; -} - -function peek_char(state: ParseState) { - return state.source[state.index]; -} - -function peek_nonwhitespace(state: ParseState) { - let index = state.index; - do { - let char = state.source[index]; - if (!/\s/.test(char)) { - return char; - } - index++; - } while (index < state.source.length); -} - -function next_char(state: ParseState) { - return state.source[state.index++]; -} - -function in_bounds(state: ParseState) { - return state.index < state.source.length; -} - -function consume_string(state: ParseState, stringChar: string) { - let inEscape; - do { - const char = next_char(state); - - if (inEscape) { - inEscape = false; - } else if (char === '\\') { - inEscape = true; - } else if (char === stringChar) { - break; - } - } while (in_bounds(state)); -} - -function consume_multiline_comment(state: ParseState) { - do { - const char = next_char(state); - - if (char === '*' && peek_char(state) === '/') { - break; - } - } while (in_bounds(state)); -} - -function consume_line_comment(state: ParseState) { - do { - const char = next_char(state); - if (char === '\n') { - break; - } - } while (in_bounds(state)); -} - -const voidElements = new Set(['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']); - -function consume_tag(state: ParseState) { - const start = state.index - 1; - let tagName = ''; - let inTag = false; - let inStart = true; - let selfClosed = false; - let inClose = false; - - let bracketIndex = 1; - do { - const char = next_char(state); - - switch (char) { - case "'": - case '"': { - consume_string(state, char); - break; - } - case '<': { - inTag = false; - tagName = ''; - - if (peek_nonwhitespace(state) === '/') { - inClose = true; - bracketIndex--; - } else { - inStart = true; - bracketIndex++; - } - break; - } - case '>': { - // An arrow function, probably - if (!inStart && !inClose) { - break; - } - - bracketIndex--; - - const addExpectedBrackets = - // Void elements don't need a closing - !voidElements.has(tagName.toLowerCase()) && - // Self-closing don't need a closing - !selfClosed && - // If we're in a start tag, we expect to find 2 more brackets - !inClose; - - if (addExpectedBrackets) { - bracketIndex += 2; - } - - inTag = false; - selfClosed = false; - inStart = false; - inClose = false; - break; - } - case ' ': { - inTag = true; - break; - } - case '/': { - if (inStart) { - selfClosed = true; - } - break; - } - default: { - if (!inTag) { - tagName += char; - } - break; - } - } - - // Unclosed tags - if (state.curlyCount <= 0) { - break; - } - - if (bracketIndex === 0) { - break; - } - } while (in_bounds(state)); - - const source = state.source.substring(start, state.index); - - const ast = parseAstro(source); - const fragment = ast.html; - - return fragment; -} - -function consume_expression(source: string, start: number): Expression { - const expr: Expression = { - type: 'Expression', - start, - end: Number.NaN, - codeChunks: [], - children: [], - }; - - let codeStart: number = start; - - const state: ParseState = { - source, - start, - index: start, - curlyCount: 1, - bracketCount: 0, - root: expr, - }; - - do { - const char = next_char(state); - - switch (char) { - case '{': { - state.curlyCount++; - break; - } - case '}': { - state.curlyCount--; - break; - } - case '<': { - const chunk = source.substring(codeStart, state.index - 1); - expr.codeChunks.push(chunk); - const tag = consume_tag(state); - expr.children.push(tag); - codeStart = state.index; - break; - } - case "'": - case '"': - case '`': { - consume_string(state, char); - break; - } - case '/': { - switch (peek_char(state)) { - case '/': { - consume_line_comment(state); - break; - } - case '*': { - consume_multiline_comment(state); - break; - } - } - } - } - } while (in_bounds(state) && state.curlyCount > 0); - - expr.end = state.index - 1; - - if (expr.children.length || !expr.codeChunks.length) { - expr.codeChunks.push(source.substring(codeStart, expr.end)); - } - - return expr; -} - -export const parse_expression_at = (source: string, index: number): Expression => { - const expression = consume_expression(source, index); - - return expression; -}; - -// @ts-ignore -export default function read_expression(parser: Parser) { - try { - const expression = parse_expression_at(parser.template, parser.index); - parser.index = expression.end; - return expression; - } catch (err) { - parser.acorn_error(err); - } -} diff --git a/src/parser/parse/read/script.ts b/src/parser/parse/read/script.ts deleted file mode 100644 index 9b8d71110..000000000 --- a/src/parser/parse/read/script.ts +++ /dev/null @@ -1,60 +0,0 @@ -// @ts-nocheck - -import type { Node } from 'estree'; -import { Parser } from '../index.js'; -import { Script } from '../../interfaces.js'; - -const script_closing_tag = '</script>'; - -function get_context(parser: Parser, attributes: any[], start: number): 'runtime' | 'setup' { - const context = attributes.find((attribute) => attribute.name === 'astro'); - if (!context) return 'runtime'; - if (context.value === true) return 'setup'; - - if (context.value.length !== 1 || context.value[0].type !== 'Text') { - parser.error( - { - code: 'invalid-script', - message: 'astro attribute must be static', - }, - start - ); - } - - const value = context.value[0].data; - - if (value !== 'setup') { - parser.error( - { - code: 'invalid-script', - message: 'If the "astro" attribute has a value, its value must be "setup"', - }, - context.start - ); - } - - return value; -} - -export default function read_script(parser: Parser, start: number, attributes: Node[]): Script { - const script_start = parser.index; - const script_end = parser.template.indexOf(script_closing_tag, script_start); - - if (script_end === -1) { - parser.error({ - code: 'unclosed-script', - message: '<script> must have a closing tag', - }); - } - - const source = parser.template.slice(0, script_start).replace(/[^\n]/g, ' ') + parser.template.slice(script_start, script_end); - parser.index = script_end + script_closing_tag.length; - - return { - type: 'Script', - start, - end: parser.index, - context: get_context(parser, attributes, start), - content: source, - }; -} diff --git a/src/parser/parse/read/style.ts b/src/parser/parse/read/style.ts deleted file mode 100644 index f23d7b10e..000000000 --- a/src/parser/parse/read/style.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Parser } from '../index.js'; -import { Style } from '../../interfaces.js'; - -interface Attribute { - start: number; - end: number; - type: 'Attribute'; - name: string; - value: { - raw: string; - data: string; - }[]; -} - -export default function read_style(parser: Parser, start: number, attributes: Attribute[]): Style { - const content_start = parser.index; - const styles = parser.read_until(/<\/style>/); - const content_end = parser.index; - parser.eat('</style>', true); - const end = parser.index; - - return { - type: 'Style', - start, - end, - attributes, - content: { - start: content_start, - end: content_end, - styles, - }, - }; -} - -function is_ref_selector(a: any, b: any) { - // TODO add CSS node types - if (!b) return false; - - return a.type === 'TypeSelector' && a.name === 'ref' && b.type === 'PseudoClassSelector'; -} |