Repository: goccy/go-yaml
Pull request #575 (2024-12-07 04:14:48)

Fix block-scalar-with-wrong-indented-line-after-spaces-only
SSIA

codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/goccy/go-yaml/pull/575?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 77.48%. Comparing base [(`783b85c`)](https://app.codecov.io/gh/goccy/go-yaml/commit/783b85ce8760f8caf20c2f66842b29dd65b9d2d5?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) to head [(`26733e1`)](https://app.codecov.io/gh/goccy/go-yaml/commit/26733e1331cae3e075939dc7419e3cff37c706d8?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima).

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #575      +/-   ##
==========================================
+ Coverage   77.41%   77.48%   +0.06%     
==========================================
  Files          21       21              
  Lines        7479     7500      +21     
==========================================
+ Hits         5790     5811      +21     
  Misses       1293     1293              
  Partials      396      396              
```

</details>

Patch:
diff --git a/scanner/context.go b/scanner/context.go
index 2529713..2ca1a13 100644
--- a/scanner/context.go
+++ b/scanner/context.go
@@ -1,7 +1,7 @@
 package scanner
 
 import (
-	"fmt"
+	"errors"
 	"strconv"
 	"strings"
 	"sync"
@@ -26,6 +26,7 @@ type Context struct {
 	docFirstLineIndentColumn int
 	docPrevLineIndentColumn  int
 	docLineIndentColumn      int
+	docSpaceOnlyIndentColumn int
 	docFoldedNewLine         bool
 }
 
@@ -63,6 +64,7 @@ func (c *Context) clear() {
 	c.docFirstLineIndentColumn = 0
 	c.docLineIndentColumn = 0
 	c.docPrevLineIndentColumn = 0
+	c.docSpaceOnlyIndentColumn = 0
 	c.docFoldedNewLine = false
 }
 
@@ -93,6 +95,7 @@ func (c *Context) breakDocument() {
 	c.docFirstLineIndentColumn = 0
 	c.docLineIndentColumn = 0
 	c.docPrevLineIndentColumn = 0
+	c.docSpaceOnlyIndentColumn = 0
 	c.docFoldedNewLine = false
 }
 
@@ -122,12 +125,29 @@ func (c *Context) updateDocumentLineIndentColumn(column int) {
 	}
 }
 
+func (c *Context) updateSpaceOnlyIndentColumn(column int) {
+	if c.docFirstLineIndentColumn != 0 {
+		return
+	}
+	c.docSpaceOnlyIndentColumn = column
+}
+
+func (c *Context) validateDocumentLineIndentAfterSpaceOnly(column int) error {
+	if c.docFirstLineIndentColumn != 0 {
+		return nil
+	}
+	if c.docSpaceOnlyIndentColumn > column {
+		return errors.New("invalid number of indent is specified after space only")
+	}
+	return nil
+}
+
 func (c *Context) validateDocumentLineIndentColumn() error {
 	if c.docFirstLineIndentColumnByDocOpt() == 0 {
 		return nil
 	}
 	if c.docFirstLineIndentColumn > c.docLineIndentColumn {
-		return fmt.Errorf("invalid number of indent is specified in the document header")
+		return errors.New("invalid number of indent is specified in the document header")
 	}
 	return nil
 }
diff --git a/scanner/scanner.go b/scanner/scanner.go
index a82ee6b..e5c7bad 100644
--- a/scanner/scanner.go
+++ b/scanner/scanner.go
@@ -755,6 +755,7 @@ func (s *Scanner) scanDocument(ctx *Context, c rune) error {
 		s.progressColumn(ctx, 1)
 	} else if s.isNewLineChar(c) {
 		ctx.addBuf(c)
+		ctx.updateSpaceOnlyIndentColumn(s.column - 1)
 		ctx.updateDocumentNewLineState()
 		s.progressLine(ctx)
 		if ctx.next() {
@@ -778,6 +779,11 @@ func (s *Scanner) scanDocument(ctx *Context, c rune) error {
 		s.progressColumn(ctx, 1)
 		return err
 	} else {
+		if err := ctx.validateDocumentLineIndentAfterSpaceOnly(s.column); err != nil {
+			invalidTk := token.Invalid(err.Error(), string(ctx.obuf), s.pos())
+			s.progressColumn(ctx, 1)
+			return ErrInvalidToken(invalidTk)
+		}
 		ctx.updateDocumentLineIndentColumn(s.column)
 		if ctx.docFirstLineIndentColumn > 0 {
 			s.lastDelimColumn = ctx.docFirstLineIndentColumn - 1


Test patch:
diff --git a/yaml_test_suite_test.go b/yaml_test_suite_test.go
index 17ca273..155efd9 100644
--- a/yaml_test_suite_test.go
+++ b/yaml_test_suite_test.go
@@ -18,22 +18,19 @@ var failureTestNames = []string{
 	"aliases-in-flow-objects",           // no json.
 	"aliases-in-explicit-block-mapping", // no json.
 	"block-mapping-with-missing-keys",   // no json.
-	"block-mapping-with-missing-values",
-	"block-mapping-with-multiline-scalars",
 	"block-scalar-with-more-spaces-than-first-content-line",
-	"block-scalar-with-wrong-indented-line-after-spaces-only",
 	"colon-at-the-beginning-of-adjacent-flow-scalar",
-	"comment-in-flow-sequence-before-comma",
+	"comment-in-flow-sequence-before-comma", // pass yamlv3.
 	"comment-without-whitespace-after-doublequoted-scalar",
 	"construct-binary",
 	"dash-in-flow-sequence",
 	"directive-variants/00",
-	"directive-variants/01",
+	"directive-variants/01", // pass yamlv3.
 	"double-quoted-scalar-with-escaped-single-quote",
-	"duplicate-yaml-directive",
+	"duplicate-yaml-directive", // pass yamlv3.
 	"escaped-slash-in-double-quotes",
-	"explicit-key-and-value-seperated-by-comment", //nolint: misspell
-	"extra-words-on-yaml-directive",
+	"explicit-key-and-value-seperated-by-comment",      //nolint: misspell // pass yamlv3.
+	"extra-words-on-yaml-directive",                    // pass yamlv3.
 	"empty-implicit-key-in-single-pair-flow-sequences", // no json.
 	"empty-keys-in-block-and-flow-mapping",             // no json.
 	"empty-lines-at-end-of-document",                   // no json.
@@ -42,54 +39,54 @@ var failureTestNames = []string{
 	"flow-collections-over-many-lines/01",
 	"flow-mapping-colon-on-line-after-key/02",
 	"flow-mapping-edge-cases",
-	"flow-sequence-with-invalid-comma-at-the-beginning",
-	"folded-block-scalar",
-	"folded-block-scalar-1-3",
-	"implicit-flow-mapping-key-on-one-line", // no json.
+	"flow-sequence-with-invalid-comma-at-the-beginning", // pass yamlv3.
+	"folded-block-scalar",                               // pass yamlv3.
+	"folded-block-scalar-1-3",                           // pass yamlv3.
+	"implicit-flow-mapping-key-on-one-line",             // no json.
 	"invalid-comment-after-comma",
 	"invalid-comment-after-end-of-flow-sequence",
 	"invalid-comma-in-tag",
-	"invalid-tag",
-	"leading-tabs-in-double-quoted/02",
-	"leading-tabs-in-double-quoted/05",
-	"legal-tab-after-indentation",
-	"literal-block-scalar-with-more-spaces-in-first-line",
-	"literal-modifers/00",
-	"literal-modifers/01",
-	"literal-modifers/02",
-	"literal-modifers/03",
-	"literal-scalars",
-	"mapping-key-and-flow-sequence-item-anchors", // no json.
-	"multiline-double-quoted-implicit-keys",
+	"invalid-tag",                                         // pass yamlv3.
+	"leading-tabs-in-double-quoted/02",                    // pass yamlv3.
+	"leading-tabs-in-double-quoted/05",                    // pass yamlv3.
+	"legal-tab-after-indentation",                         // pass yamlv3.
+	"literal-block-scalar-with-more-spaces-in-first-line", // pass yamlv3.
+	"literal-modifers/00",                                 // pass yamlv3.
+	"literal-modifers/01",                                 // pass yamlv3.
+	"literal-modifers/02",                                 // pass yamlv3.
+	"literal-modifers/03",                                 // pass yamlv3.
+	"literal-scalars",                                     // pass yamlv3.
+	"mapping-key-and-flow-sequence-item-anchors",          // no json.
+	"multiline-double-quoted-implicit-keys",               // pass yamlv3.
 	"multiline-plain-flow-mapping-key",
-	"multiline-plain-value-with-tabs-on-empty-lines",
-	"multiline-scalar-at-top-level",
-	"multiline-scalar-at-top-level-1-3",
-	"multiline-single-quoted-implicit-keys",
-	"multiline-unidented-double-quoted-block-key",
-	"nested-implicit-complex-keys", // no json.
-	"node-anchor-not-indented",
+	"multiline-plain-value-with-tabs-on-empty-lines", // pass yamlv3.
+	"multiline-scalar-at-top-level",                  // pass yamlv3.
+	"multiline-scalar-at-top-level-1-3",              // pass yamlv3.
+	"multiline-single-quoted-implicit-keys",          // pass yamlv3.
+	"multiline-unidented-double-quoted-block-key",    // pass yamlv3.
+	"nested-implicit-complex-keys",                   // no json.
+	"node-anchor-not-indented",                       // pass yamlv3.
 	"plain-dashes-in-flow-sequence",
-	"plain-url-in-flow-mapping",
-	"question-mark-edge-cases/00", // no json.
-	"question-mark-edge-cases/01", // no json.
-	"scalar-doc-with-in-content/01",
-	"scalar-value-with-two-anchors",
-	"single-character-streams/01",                      // no json.
-	"single-pair-implicit-entries",                     // no json.
-	"spec-example-2-11-mapping-between-sequences",      // no json.
-	"spec-example-6-12-separation-spaces",              // no json.
-	"spec-example-7-16-flow-mapping-entries",           // no json.
-	"spec-example-7-3-completely-empty-flow-nodes",     // no json.
-	"spec-example-8-18-implicit-block-mapping-entries", // no json.
-	"spec-example-8-19-compact-block-mappings",         // no json.
-	"spec-example-6-19-secondary-tag-handle",
-	"spec-example-6-24-verbatim-tags",
-	"spec-example-6-6-line-folding",
-	"spec-example-6-6-line-folding-1-3",
-	"spec-example-6-8-flow-folding",
-	"spec-example-8-10-folded-lines-8-13-final-empty-lines",
-	"spec-example-8-17-explicit-block-mapping-entries",
+	"plain-url-in-flow-mapping",                             // pass yamlv3.
+	"question-mark-edge-cases/00",                           // no json.
+	"question-mark-edge-cases/01",                           // no json.
+	"scalar-doc-with-in-content/01",                         // pass yamlv3.
+	"scalar-value-with-two-anchors",                         // pass yamlv3.
+	"single-character-streams/01",                           // no json.
+	"single-pair-implicit-entries",                          // no json.
+	"spec-example-2-11-mapping-between-sequences",           // no json.
+	"spec-example-6-12-separation-spaces",                   // no json.
+	"spec-example-7-16-flow-mapping-entries",                // no json.
+	"spec-example-7-3-completely-empty-flow-nodes",          // no json.
+	"spec-example-8-18-implicit-block-mapping-entries",      // no json.
+	"spec-example-8-19-compact-block-mappings",              // no json.
+	"spec-example-6-19-secondary-tag-handle",                // pass yamlv3.
+	"spec-example-6-24-verbatim-tags",                       // pass yamlv3.
+	"spec-example-6-6-line-folding",                         // pass yamlv3.
+	"spec-example-6-6-line-folding-1-3",                     // pass yamlv3.
+	"spec-example-6-8-flow-folding",                         // pass yamlv3.
+	"spec-example-8-10-folded-lines-8-13-final-empty-lines", // pass yamlv3.
+	"spec-example-8-17-explicit-block-mapping-entries",      // pass yamlv3.
 	"spec-example-8-2-block-indentation-indicator",
 	"spec-example-9-3-bare-documents",
 	"spec-example-9-4-explicit-documents",
@@ -101,14 +98,14 @@ var failureTestNames = []string{
 	"tabs-in-various-contexts/003",
 	"tabs-that-look-like-indentation/00",
 	"tabs-that-look-like-indentation/01",
-	"tabs-that-look-like-indentation/02",
+	"tabs-that-look-like-indentation/02", // pass yamlv3.
 	"tabs-that-look-like-indentation/03",
 	"tabs-that-look-like-indentation/04",
-	"tabs-that-look-like-indentation/05",
+	"tabs-that-look-like-indentation/05", // pass yamlv3.
 	"tabs-that-look-like-indentation/07",
-	"tabs-that-look-like-indentation/08",
+	"tabs-that-look-like-indentation/08", // pass yamlv3.
 	"tag-shorthand-used-in-documents-but-only-defined-in-the-first",
-	"tags-for-block-objects",
+	"tags-for-block-objects",                           // pass yamlv3.
 	"tags-on-empty-scalars",                            // no json.
 	"trailing-line-of-spaces/01",                       // last '\n' character is needed ?
 	"various-combinations-of-explicit-block-mappings",  // no json.