From dd6e490a8ed499a362c6fe692155c7eba4732740 Mon Sep 17 00:00:00 2001 From: Eljees <3.14hell@gmail.com> Date: Thu, 6 Aug 2026 20:44:17 +0300 Subject: [PATCH] parser: keep the newline that ends a heredoc terminator line The heredoc terminator consumed the line break that follows the marker, so the top level parser had nothing left to accept as the separator before the next instruction. A comment or an instruction placed directly after a heredoc failed to parse, while an empty line or a leading space made the error go away. Stop at the marker and only look ahead for the newline. The delimiter of an empty heredoc has the same shape and is fixed the same way. closes #99 related-to: hadolint/hadolint#960 Signed-off-by: Eljees <3.14hell@gmail.com> --- src/Language/Docker/Parser/Prelude.hs | 7 +++++-- test/Language/Docker/ParseCopySpec.hs | 20 ++++++++++++++++++++ test/Language/Docker/ParseRunSpec.hs | 24 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/Language/Docker/Parser/Prelude.hs b/src/Language/Docker/Parser/Prelude.hs index 1ca7bf9..3334173 100644 --- a/src/Language/Docker/Parser/Prelude.hs +++ b/src/Language/Docker/Parser/Prelude.hs @@ -202,8 +202,11 @@ heredocContent marker = do termination :: Parser Text termination = try terEOL <|> terEOF + -- The line break that follows the terminating marker is not part of the + -- heredoc: it is the line break that separates this instruction from + -- whatever comes next, so it is left for the caller to consume. terEOL :: Parser Text - terEOL = string $ "\n" <> marker <> "\n" + terEOL = string ("\n" <> marker) <* lookAhead (char '\n') terEOF :: Parser Text terEOF = do @@ -215,7 +218,7 @@ heredocContent marker = do delimiter = try delEOL <|> delEOF delEOL :: Parser Text - delEOL = string $ marker <> "\n" + delEOL = string marker <* lookAhead (char '\n') delEOF :: Parser Text delEOF = do diff --git a/test/Language/Docker/ParseCopySpec.hs b/test/Language/Docker/ParseCopySpec.hs index 25aeb49..dd6c3a1 100644 --- a/test/Language/Docker/ParseCopySpec.hs +++ b/test/Language/Docker/ParseCopySpec.hs @@ -314,3 +314,23 @@ spec = do ( CopyArgs [ SourcePath "FOO" ] ( TargetPath "/target" ) ) def ] + it "heredoc followed by another instruction" $ + let file = Text.unlines ["COPY <