a generic snippet's type parameters are parsed, not scanned: <T extends () => void> works and bracket.js is gone

goodbye-acorn
Nic 1 day ago
parent 6632b93c8b
commit 5d7a91864c

@ -162,6 +162,14 @@ export function read_params(parser) {
return answer.params;
}
/**
* @param {Parser} parser at the opening `<`
*/
export function read_type_parameters(parser) {
const start = parser.index;
read(parser, (js) => js.parseTypeParametersAt(start));
}
/**
* @param {Parser} parser
* @returns {Statement}

@ -3,8 +3,7 @@
/** @import { Parser } from '../index.js' */
import * as e from '../../../errors.js';
import { create_fragment, ExpressionMetadata } from '../../nodes.js';
import { read_expression, read_params, read_pattern, read_statement } from '../js.js';
import { match_bracket } from '../utils/bracket.js';
import { read_expression, read_params, read_pattern, read_statement, read_type_parameters } from '../js.js';
const regex_whitespace_with_closing_curly_brace = /\s*}/y;
const regex_supported_declaration = /(?:let|const)\b/y;
@ -12,7 +11,6 @@ const regex_unsupported_declaration = /(?:var|interface|enum)\b/y;
// `type` is a contextual keyword; this is just a shape hint, confirmed by parsing.
const regex_maybe_type_declaration = /type\b/y;
const pointy_bois = { '<': '>' };
/** @param {Parser} parser */
export default function tag(parser) {
@ -299,14 +297,10 @@ function open(parser) {
/** @type {string | undefined} */
let type_params;
// if we match a generic opening
if (parser.ts && parser.match('<')) {
const start = parser.index;
const end = match_bracket(parser, start, pointy_bois);
type_params = parser.template.slice(start + 1, end - 1);
parser.index = end;
read_type_parameters(parser);
type_params = parser.template.slice(start + 1, parser.index - 1);
}
parser.allow_whitespace();

@ -1,82 +0,0 @@
/** @import { Parser } from '../index.js' */
import * as e from '../../../errors.js';
/** @type {Record<string, string>} */
const default_brackets = {
'{': '}',
'(': ')',
'[': ']'
};
const default_close = new Set(Object.values(default_brackets));
/**
* @param {Parser} parser
* @param {number} start
* @param {Record<string, string>} brackets
*/
export function match_bracket(parser, start, brackets = default_brackets) {
const close = brackets === default_brackets ? default_close : new Set(Object.values(brackets));
const bracket_stack = [];
let i = start;
while (i < parser.template.length) {
let char = parser.template[i++];
if (char === "'" || char === '"' || char === '`') {
i = match_quote(parser, i, char);
continue;
}
if (char in brackets) {
bracket_stack.push(char);
} else if (close.has(char)) {
const popped = /** @type {string} */ (bracket_stack.pop());
const expected = /** @type {string} */ (brackets[popped]);
if (char !== expected) {
e.expected_token(i - 1, expected);
}
if (bracket_stack.length === 0) {
return i;
}
}
}
e.unexpected_eof(parser.template.length);
}
/**
* @param {Parser} parser
* @param {number} start
* @param {string} quote
*/
function match_quote(parser, start, quote) {
let is_escaped = false;
let i = start;
while (i < parser.template.length) {
const char = parser.template[i++];
if (is_escaped) {
is_escaped = false;
continue;
}
if (char === quote) {
return i;
}
if (char === '\\') {
is_escaped = true;
}
if (quote === '`' && char === '$' && parser.template[i] === '{') {
i = match_bracket(parser, i);
}
}
e.unterminated_string_constant(start);
}

@ -0,0 +1,6 @@
<script lang="ts">
</script>
{#snippet foo<T extends () => void, U = Array<string>>(x: T, y: U)}
{x}
{/snippet}

@ -0,0 +1,263 @@
{
"css": null,
"js": [],
"start": 0,
"end": 113,
"type": "Root",
"fragment": {
"type": "Fragment",
"nodes": [
{
"type": "Text",
"start": 28,
"end": 30,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "SnippetBlock",
"start": 30,
"end": 113,
"expression": {
"type": "Identifier",
"name": "foo",
"start": 40,
"end": 43,
"loc": {
"start": {
"line": 4,
"column": 10,
"character": 40
},
"end": {
"line": 4,
"column": 13,
"character": 43
}
}
},
"typeParams": "T extends () => void, U = Array<string>",
"parameters": [
{
"type": "Identifier",
"start": 85,
"end": 89,
"loc": {
"start": {
"line": 4,
"column": 55
},
"end": {
"line": 4,
"column": 59
}
},
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 86,
"end": 89,
"loc": {
"start": {
"line": 4,
"column": 56
},
"end": {
"line": 4,
"column": 59
}
},
"typeAnnotation": {
"type": "TSTypeReference",
"start": 88,
"end": 89,
"loc": {
"start": {
"line": 4,
"column": 58
},
"end": {
"line": 4,
"column": 59
}
},
"typeName": {
"type": "Identifier",
"start": 88,
"end": 89,
"loc": {
"start": {
"line": 4,
"column": 58
},
"end": {
"line": 4,
"column": 59
}
},
"name": "T"
}
}
},
"name": "x"
},
{
"type": "Identifier",
"start": 91,
"end": 95,
"loc": {
"start": {
"line": 4,
"column": 61
},
"end": {
"line": 4,
"column": 65
}
},
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 92,
"end": 95,
"loc": {
"start": {
"line": 4,
"column": 62
},
"end": {
"line": 4,
"column": 65
}
},
"typeAnnotation": {
"type": "TSTypeReference",
"start": 94,
"end": 95,
"loc": {
"start": {
"line": 4,
"column": 64
},
"end": {
"line": 4,
"column": 65
}
},
"typeName": {
"type": "Identifier",
"start": 94,
"end": 95,
"loc": {
"start": {
"line": 4,
"column": 64
},
"end": {
"line": 4,
"column": 65
}
},
"name": "U"
}
}
},
"name": "y"
}
],
"body": {
"type": "Fragment",
"nodes": [
{
"type": "Text",
"start": 97,
"end": 99,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "ExpressionTag",
"start": 99,
"end": 102,
"expression": {
"type": "Identifier",
"start": 100,
"end": 101,
"loc": {
"start": {
"line": 5,
"column": 2
},
"end": {
"line": 5,
"column": 3
}
},
"name": "x"
}
},
{
"type": "Text",
"start": 102,
"end": 103,
"raw": "\n",
"data": "\n"
}
]
}
}
]
},
"options": null,
"comments": [],
"instance": {
"type": "Script",
"start": 0,
"end": 28,
"context": "default",
"content": {
"type": "Program",
"start": 18,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 9
}
},
"body": [],
"sourceType": "module"
},
"attributes": [
{
"type": "Attribute",
"start": 8,
"end": 17,
"name": "lang",
"name_loc": {
"start": {
"line": 1,
"column": 8,
"character": 8
},
"end": {
"line": 1,
"column": 12,
"character": 12
}
},
"value": [
{
"start": 14,
"end": 16,
"type": "Text",
"raw": "ts",
"data": "ts"
}
]
}
]
}
}
Loading…
Cancel
Save