mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
Restrict strings beginning with quote should also ending with quote (#13131)
# Description Closes: #13010 It adds an additional check inside `parse_string`, and returns `unbalanced quote` if input string is unbalanced # User-Facing Changes After this pr, the following is no longer allowed: ```nushell ❯ "asdfasdf"asdfasdf Error: nu::parser::extra_token_after_closing_delimiter × Invaild characters after closing delimiter ╭─[entry #1:1:11] 1 │ "asdfasdf"asdfasdf · ────┬─── · ╰── invalid characters ╰──── help: Try removing them. ❯ 'asdfasd'adsfadf Error: nu::parser::extra_token_after_closing_delimiter × Invaild characters after closing delimiter ╭─[entry #2:1:10] 1 │ 'asdfasd'adsfadf · ───┬─── · ╰── invalid characters ╰──── help: Try removing them. ``` # Tests + Formatting Added 1 test
This commit is contained in:
parent
1f1f581357
commit
57452337ff
3 changed files with 44 additions and 0 deletions
|
@ -2828,6 +2828,36 @@ pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression
|
||||||
if bytes[0] != b'\'' && bytes[0] != b'"' && bytes[0] != b'`' && bytes.contains(&b'(') {
|
if bytes[0] != b'\'' && bytes[0] != b'"' && bytes[0] != b'`' && bytes.contains(&b'(') {
|
||||||
return parse_string_interpolation(working_set, span);
|
return parse_string_interpolation(working_set, span);
|
||||||
}
|
}
|
||||||
|
// Check for unbalanced quotes:
|
||||||
|
{
|
||||||
|
if bytes.starts_with(b"\"")
|
||||||
|
&& (bytes.iter().filter(|ch| **ch == b'"').count() > 1 && !bytes.ends_with(b"\""))
|
||||||
|
{
|
||||||
|
let close_delimiter_index = bytes
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.position(|ch| *ch == b'"')
|
||||||
|
.expect("Already check input bytes contains at least two double quotes");
|
||||||
|
// needs `+2` rather than `+1`, because we have skip 1 to find close_delimiter_index before.
|
||||||
|
let span = Span::new(span.start + close_delimiter_index + 2, span.end);
|
||||||
|
working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(span));
|
||||||
|
return garbage(working_set, span);
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.starts_with(b"\'")
|
||||||
|
&& (bytes.iter().filter(|ch| **ch == b'\'').count() > 1 && !bytes.ends_with(b"\'"))
|
||||||
|
{
|
||||||
|
let close_delimiter_index = bytes
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.position(|ch| *ch == b'\'')
|
||||||
|
.expect("Already check input bytes contains at least two double quotes");
|
||||||
|
// needs `+2` rather than `+1`, because we have skip 1 to find close_delimiter_index before.
|
||||||
|
let span = Span::new(span.start + close_delimiter_index + 2, span.end);
|
||||||
|
working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(span));
|
||||||
|
return garbage(working_set, span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (s, err) = unescape_unquote_string(bytes, span);
|
let (s, err) = unescape_unquote_string(bytes, span);
|
||||||
if let Some(err) = err {
|
if let Some(err) = err {
|
||||||
|
|
|
@ -17,6 +17,13 @@ pub enum ParseError {
|
||||||
#[diagnostic(code(nu::parser::extra_tokens), help("Try removing them."))]
|
#[diagnostic(code(nu::parser::extra_tokens), help("Try removing them."))]
|
||||||
ExtraTokens(#[label = "extra tokens"] Span),
|
ExtraTokens(#[label = "extra tokens"] Span),
|
||||||
|
|
||||||
|
#[error("Invalid characters after closing delimiter")]
|
||||||
|
#[diagnostic(
|
||||||
|
code(nu::parser::extra_token_after_closing_delimiter),
|
||||||
|
help("Try removing them.")
|
||||||
|
)]
|
||||||
|
ExtraTokensAfterClosingDelimiter(#[label = "invalid characters"] Span),
|
||||||
|
|
||||||
#[error("Extra positional argument.")]
|
#[error("Extra positional argument.")]
|
||||||
#[diagnostic(code(nu::parser::extra_positional), help("Usage: {0}"))]
|
#[diagnostic(code(nu::parser::extra_positional), help("Usage: {0}"))]
|
||||||
ExtraPositional(String, #[label = "extra positional argument"] Span),
|
ExtraPositional(String, #[label = "extra positional argument"] Span),
|
||||||
|
@ -577,6 +584,7 @@ impl ParseError {
|
||||||
ParseError::LabeledErrorWithHelp { span: s, .. } => *s,
|
ParseError::LabeledErrorWithHelp { span: s, .. } => *s,
|
||||||
ParseError::RedirectingBuiltinCommand(_, s, _) => *s,
|
ParseError::RedirectingBuiltinCommand(_, s, _) => *s,
|
||||||
ParseError::UnexpectedSpreadArg(_, s) => *s,
|
ParseError::UnexpectedSpreadArg(_, s) => *s,
|
||||||
|
ParseError::ExtraTokensAfterClosingDelimiter(s) => *s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,12 @@ fn non_string_in_record() -> TestResult {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbalance_string() -> TestResult {
|
||||||
|
fail_test(r#""aaaab"cc"#, "invalid characters")?;
|
||||||
|
fail_test(r#"'aaaab'cc"#, "invalid characters")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_in_valuestream() -> TestResult {
|
fn string_in_valuestream() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
|
|
Loading…
Reference in a new issue