fix lexing strings containing escaped quotation characters
This commit is contained in:
parent
b60bb6e2d6
commit
673b8e941a
|
@ -750,54 +750,54 @@ class Parser
|
|||
return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs);
|
||||
}
|
||||
|
||||
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
|
||||
switch ($value[0] ?? '') {
|
||||
case '"':
|
||||
case "'":
|
||||
$cursor = \strlen($this->currentLine) - \strlen($value);
|
||||
$parsedValue = Inline::parse($this->lexInlineQuotedString($cursor), $flags, $this->refs);
|
||||
|
||||
// do not take following lines into account when the current line is a quoted single line value
|
||||
if (null !== $quotation && self::preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) {
|
||||
return Inline::parse($value, $flags, $this->refs);
|
||||
if (isset($this->currentLine[$cursor]) && preg_replace('/\s*#.*$/A', '', substr($this->currentLine, $cursor))) {
|
||||
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($this->currentLine, $cursor)));
|
||||
}
|
||||
|
||||
return $parsedValue;
|
||||
default:
|
||||
$lines = [];
|
||||
|
||||
while ($this->moveToNextLine()) {
|
||||
// unquoted strings end before the first unindented line
|
||||
if (0 === $this->getCurrentLineIndentation()) {
|
||||
$this->moveToPreviousLine();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$lines[] = trim($this->currentLine);
|
||||
}
|
||||
|
||||
for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
|
||||
if ('' === $lines[$i]) {
|
||||
$value .= "\n";
|
||||
$previousLineBlank = true;
|
||||
} elseif ($previousLineBlank) {
|
||||
$value .= $lines[$i];
|
||||
$previousLineBlank = false;
|
||||
} else {
|
||||
$value .= ' '.$lines[$i];
|
||||
$previousLineBlank = false;
|
||||
}
|
||||
}
|
||||
|
||||
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
|
||||
|
||||
$parsedValue = Inline::parse($value, $flags, $this->refs);
|
||||
|
||||
if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
|
||||
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
|
||||
}
|
||||
|
||||
return $parsedValue;
|
||||
}
|
||||
|
||||
$lines = [];
|
||||
|
||||
while ($this->moveToNextLine()) {
|
||||
// unquoted strings end before the first unindented line
|
||||
if (null === $quotation && 0 === $this->getCurrentLineIndentation()) {
|
||||
$this->moveToPreviousLine();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$lines[] = trim($this->currentLine);
|
||||
|
||||
// quoted string values end with a line that is terminated with the quotation character
|
||||
$escapedLine = str_replace(['\\\\', '\\"'], '', $this->currentLine);
|
||||
if ('' !== $escapedLine && substr($escapedLine, -1) === $quotation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
|
||||
if ('' === $lines[$i]) {
|
||||
$value .= "\n";
|
||||
$previousLineBlank = true;
|
||||
} elseif ($previousLineBlank) {
|
||||
$value .= $lines[$i];
|
||||
$previousLineBlank = false;
|
||||
} else {
|
||||
$value .= ' '.$lines[$i];
|
||||
$previousLineBlank = false;
|
||||
}
|
||||
}
|
||||
|
||||
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
|
||||
|
||||
$parsedValue = Inline::parse($value, $flags, $this->refs);
|
||||
|
||||
if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
|
||||
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
|
||||
}
|
||||
|
||||
return $parsedValue;
|
||||
} catch (ParseException $e) {
|
||||
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
|
||||
$e->setSnippet($this->currentLine);
|
||||
|
@ -1154,8 +1154,13 @@ class Parser
|
|||
|
||||
$previousLineWasNewline = true;
|
||||
$previousLineWasTerminatedWithBackslash = false;
|
||||
$lineNumber = 0;
|
||||
|
||||
do {
|
||||
if (++$lineNumber > 1) {
|
||||
$cursor += strspn($this->currentLine, ' ', $cursor);
|
||||
}
|
||||
|
||||
if ($this->isCurrentLineBlank()) {
|
||||
$value .= "\n";
|
||||
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
|
||||
|
|
|
@ -1570,6 +1570,54 @@ EOT;
|
|||
$this->assertSame(['foo' => 'bar baz foobar foo', 'bar' => 'baz'], $this->parser->parse($yaml));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider escapedQuotationCharactersInQuotedStrings
|
||||
*/
|
||||
public function testParseQuotedStringContainingEscapedQuotationCharacters(string $yaml, array $expected)
|
||||
{
|
||||
$this->assertSame($expected, $this->parser->parse($yaml));
|
||||
}
|
||||
|
||||
public function escapedQuotationCharactersInQuotedStrings()
|
||||
{
|
||||
return [
|
||||
'single quoted string' => [
|
||||
<<<YAML
|
||||
entries:
|
||||
- message: 'No emails received before timeout - Address: ''test@testemail.company.com''
|
||||
Keyword: ''Your Order confirmation'' ttl: 50'
|
||||
outcome: failed
|
||||
YAML
|
||||
,
|
||||
[
|
||||
'entries' => [
|
||||
[
|
||||
'message' => 'No emails received before timeout - Address: \'test@testemail.company.com\' Keyword: \'Your Order confirmation\' ttl: 50',
|
||||
'outcome' => 'failed',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'double quoted string' => [
|
||||
<<<YAML
|
||||
entries:
|
||||
- message: "No emails received before timeout - Address: \"test@testemail.company.com\"
|
||||
Keyword: \"Your Order confirmation\" ttl: 50"
|
||||
outcome: failed
|
||||
YAML
|
||||
,
|
||||
[
|
||||
'entries' => [
|
||||
[
|
||||
'message' => 'No emails received before timeout - Address: "test@testemail.company.com" Keyword: "Your Order confirmation" ttl: 50',
|
||||
'outcome' => 'failed',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testParseMultiLineString()
|
||||
{
|
||||
$this->assertEquals("foo bar\nbaz", $this->parser->parse("foo\nbar\n\nbaz"));
|
||||
|
|
Reference in New Issue