mirror of https://github.com/sveltejs/svelte
fix: warn on bidirectional control characters, fix various issues with template expressions (#15893)
* fix: warn on bidirectional control characters * check evaluated values as well, fix minor issue * fix failing tests * lint * fix * shrink warning code * use validator test suite rather than snapshot (which should be used sparingly as it creates more git noise) * show ranges during parsing, and warn on all occurrences rather than just the first * fix lint * move check into Text visitor so it happens in expected order * unused * add svelte-ignore test * ignore control characters following a svelte-ignore comment * tweak message * no need to test evaluations, since we are already testing the literals that they are composed of --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/15899/head
parent
92cdeadadf
commit
aa041a9e65
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: warn on bidirectional control characters
|
@ -0,0 +1,14 @@
|
||||
/** @import { Literal } from 'estree' */
|
||||
import * as w from '../../../warnings.js';
|
||||
import { regex_bidirectional_control_characters } from '../../patterns.js';
|
||||
|
||||
/**
|
||||
* @param {Literal} node
|
||||
*/
|
||||
export function Literal(node) {
|
||||
if (typeof node.value === 'string') {
|
||||
if (regex_bidirectional_control_characters.test(node.value)) {
|
||||
w.bidirectional_control_characters(node);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
/** @import { TemplateElement } from 'estree' */
|
||||
import * as w from '../../../warnings.js';
|
||||
import { regex_bidirectional_control_characters } from '../../patterns.js';
|
||||
|
||||
/**
|
||||
* @param {TemplateElement} node
|
||||
*/
|
||||
export function TemplateElement(node) {
|
||||
if (regex_bidirectional_control_characters.test(node.value.cooked ?? '')) {
|
||||
w.bidirectional_control_characters(node);
|
||||
}
|
||||
}
|
@ -1,20 +1,52 @@
|
||||
/** @import { AST } from '#compiler' */
|
||||
/** @import { Context } from '../types' */
|
||||
import { is_tag_valid_with_parent } from '../../../../html-tree-validation.js';
|
||||
import { regex_not_whitespace } from '../../patterns.js';
|
||||
import { regex_bidirectional_control_characters, regex_not_whitespace } from '../../patterns.js';
|
||||
import * as e from '../../../errors.js';
|
||||
import * as w from '../../../warnings.js';
|
||||
import { extract_svelte_ignore } from '../../../utils/extract_svelte_ignore.js';
|
||||
|
||||
/**
|
||||
* @param {AST.Text} node
|
||||
* @param {Context} context
|
||||
*/
|
||||
export function Text(node, context) {
|
||||
const in_template = context.path.at(-1)?.type === 'Fragment';
|
||||
const parent = /** @type {AST.SvelteNode} */ (context.path.at(-1));
|
||||
|
||||
if (in_template && context.state.parent_element && regex_not_whitespace.test(node.data)) {
|
||||
if (
|
||||
parent.type === 'Fragment' &&
|
||||
context.state.parent_element &&
|
||||
regex_not_whitespace.test(node.data)
|
||||
) {
|
||||
const message = is_tag_valid_with_parent('#text', context.state.parent_element);
|
||||
if (message) {
|
||||
e.node_invalid_placement(node, message);
|
||||
}
|
||||
}
|
||||
|
||||
regex_bidirectional_control_characters.lastIndex = 0;
|
||||
for (const match of node.data.matchAll(regex_bidirectional_control_characters)) {
|
||||
let is_ignored = false;
|
||||
|
||||
// if we have a svelte-ignore comment earlier in the text, bail
|
||||
// (otherwise we can only use svelte-ignore on parent elements/blocks)
|
||||
if (parent.type === 'Fragment') {
|
||||
for (const child of parent.nodes) {
|
||||
if (child === node) break;
|
||||
|
||||
if (child.type === 'Comment') {
|
||||
is_ignored ||= extract_svelte_ignore(
|
||||
child.start + 4,
|
||||
child.data,
|
||||
context.state.analysis.runes
|
||||
).includes('bidirectional_control_characters');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_ignored) {
|
||||
let start = match.index + node.start;
|
||||
w.bidirectional_control_characters({ start, end: start + match[0].length });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"code": "bidirectional_control_characters",
|
||||
"message": "A bidirectional control character was detected in your code. These characters can be used to alter the visual direction of your code and could have unintended consequences",
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 58
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "bidirectional_control_characters",
|
||||
"message": "A bidirectional control character was detected in your code. These characters can be used to alter the visual direction of your code and could have unintended consequences",
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "bidirectional_control_characters",
|
||||
"message": "A bidirectional control character was detected in your code. These characters can be used to alter the visual direction of your code and could have unintended consequences",
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 5
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "bidirectional_control_characters",
|
||||
"message": "A bidirectional control character was detected in your code. These characters can be used to alter the visual direction of your code and could have unintended consequences",
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 12
|
||||
}
|
||||
}
|
||||
]
|
Loading…
Reference in new issue