fix: generalize lang="ts" hint to all template expression contexts

Instead of only hinting on snippet params, detect TypeScript syntax
across all expression sites: acorn_error catches colon annotations
that make acorn fail, read_expression catches as/satisfies/!/: that
acorn silently skips over.
pull/17954/head
Julia 5 months ago
parent 9d0edf720e
commit 40e296656e

@ -177,11 +177,17 @@ export class Parser {
/** /**
* @param {any} err * @param {any} err
* @param {string} [suffix]
* @returns {never} * @returns {never}
*/ */
acorn_error(err, suffix = '') { acorn_error(err) {
e.js_parse_error(err.pos, err.message.replace(regex_position_indicator, '') + suffix); const message = err.message.replace(regex_position_indicator, '');
const hint =
!this.ts && typeof err.pos === 'number' && this.template[err.pos] === ':'
? ` (did you forget to add \`lang="ts"\`?)`
: '';
e.js_parse_error(err.pos, message + hint);
} }
/** /**

@ -33,14 +33,19 @@ export function get_loose_identifier(parser, opening_token) {
* @returns {Expression} * @returns {Expression}
*/ */
export default function read_expression(parser, opening_token, disallow_loose) { export default function read_expression(parser, opening_token, disallow_loose) {
/** @type {Expression | undefined} */
let node;
try { try {
let comment_index = parser.root.comments.length; let comment_index = parser.root.comments.length;
const node = parse_expression_at( node = /** @type {Expression} */ (
parser.template, parse_expression_at(
parser.root.comments, parser.template,
parser.ts, parser.root.comments,
parser.index parser.ts,
parser.index
)
); );
let num_parens = 0; let num_parens = 0;
@ -76,8 +81,6 @@ export default function read_expression(parser, opening_token, disallow_loose) {
} }
parser.index = index; parser.index = index;
return /** @type {Expression} */ (node);
} catch (err) { } catch (err) {
// If we are in an each loop we need the error to be thrown in cases like // If we are in an each loop we need the error to be thrown in cases like
// `as { y = z }` so we still throw and handle the error there // `as { y = z }` so we still throw and handle the error there
@ -90,4 +93,22 @@ export default function read_expression(parser, opening_token, disallow_loose) {
parser.acorn_error(err); parser.acorn_error(err);
} }
if (!parser.ts) {
let j = parser.index;
while (j < parser.template.length && regex_whitespace.test(parser.template[j])) j++;
const remaining = parser.template.slice(j);
if (
remaining[0] === ':' ||
/^satisfies[\s(]/.test(remaining) ||
(remaining[0] === '!' && remaining[1] !== '=') ||
(/^as[\s(]/.test(remaining) && !disallow_loose)
) {
e.js_parse_error(j, `Unexpected token (did you forget to add \`lang="ts"\`?)`);
}
}
return node;
} }

@ -403,11 +403,7 @@ function open(parser) {
) )
); );
} catch (/** @type {any} */ err) { } catch (/** @type {any} */ err) {
const suffix = parser.acorn_error(err);
!parser.ts && parser.template[err.pos] === ':'
? ` (did you forget to add \`lang="ts"\`?)`
: '';
parser.acorn_error(err, suffix);
} }
} else { } else {
function_expression = { params: [] }; function_expression = { params: [] };

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'js_parse_error',
message: 'Unexpected token (did you forget to add `lang="ts"`?)',
position: [3, 3]
}
});

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'js_parse_error',
message: 'Unexpected token (did you forget to add `lang="ts"`?)',
position: [14, 14]
}
});

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'js_parse_error',
message: 'Unexpected token (did you forget to add `lang="ts"`?)',
position: [2, 2]
}
});

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'js_parse_error',
message: 'Unexpected token (did you forget to add `lang="ts"`?)',
position: [2, 2]
}
});

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'js_parse_error',
message: 'Unexpected token (did you forget to add `lang="ts"`?)',
position: [3, 3]
}
});
Loading…
Cancel
Save