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 { AST } from '#compiler' */
|
||||||
/** @import { Context } from '../types' */
|
/** @import { Context } from '../types' */
|
||||||
import { is_tag_valid_with_parent } from '../../../../html-tree-validation.js';
|
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 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 {AST.Text} node
|
||||||
* @param {Context} context
|
* @param {Context} context
|
||||||
*/
|
*/
|
||||||
export function Text(node, 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);
|
const message = is_tag_valid_with_parent('#text', context.state.parent_element);
|
||||||
if (message) {
|
if (message) {
|
||||||
e.node_invalid_placement(node, 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