Skip to content

Commit 52c3b64

Browse files
authored
Add feature strip_directives (#217)
* Add feature `strip_directives` This PR adds the `strip_directives` feature, a hotfix that will allow yamlfmt to function with directives in the document for some cases. It's a very imperfect feature but should help in some minimal cases. * add missing license header
1 parent 399324c commit 52c3b64

File tree

18 files changed

+180
-19
lines changed

18 files changed

+180
-19
lines changed

docs/config-file.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,30 @@ The basic formatter is a barebones formatter that simply takes the data provided
7777
| `retain_line_breaks` | bool | false | Retain line breaks in formatted yaml. |
7878
| `retain_line_breaks_single` | bool | false | (NOTE: Takes precedence over `retain_line_breaks`) Retain line breaks in formatted yaml, but only keep a single line in groups of many blank lines. |
7979
| `disallow_anchors` | bool | false | If true, reject any YAML anchors or aliases found in the document. |
80-
| `max_line_length` | int | 0 | Set the maximum line length (see notes below). if not set, defaults to 0 which means no limit. |
80+
| `max_line_length` | int | 0 | Set the maximum line length ([see note below](#max_line_length)). if not set, defaults to 0 which means no limit. |
8181
| `scan_folded_as_literal` | bool | false | Option that will preserve newlines in folded block scalars (blocks that start with `>`). |
8282
| `indentless_arrays` | bool | false | Render `-` array items (block sequence items) without an increased indent. |
8383
| `drop_merge_tag` | bool | false | Assume that any well formed merge using just a `<<` token will be a merge, and drop the `!!merge` tag from the formatted result. |
8484
| `pad_line_comments` | int | 1 | The number of padding spaces to insert before line comments. |
8585
| `trim_trailing_whitespace` | bool | false | Trim trailing whitespace from lines. |
8686
| `eof_newline` | bool | false | Always add a newline at end of file. Useful in the scenario where `retain_line_breaks` is disabled but the trailing newline is still needed. |
87+
| `strip_directives` | bool | false | [YAML Directives](https://yaml.org/spec/1.2.2/#3234-directives) are not supported by this formatter. This feature will attempt to strip the directives before formatting and put them back. [Use this feature at your own risk.](#strip_directives) |
8788

88-
### Note on `max_line_length`
89+
## Additional Notes
90+
91+
### `max_line_length`
8992

9093
It's not perfect; it uses the `best_width` setting from the [gopkg.in/yaml.v3][1] library. If there's a very long token that extends too far for the line width, it won't split it up properly. I will keep trying to make this work better, but decided to get a version of the feature in that works for a lot of scenarios even if not all of them.
9194

95+
### `strip_directives`
96+
97+
TL;DR:
98+
* If you only have directives at the top of the file this feature will work just fine, otherwise make sure you test it first.
99+
* Please note that directives are completely tossed and ignored by the formatter
100+
101+
This hotfix is flaky. It is very hard to reconstruct data like this without parsing or knowing what may have changed about the structure of the document. What it attempts to do is find the directives in the document before formatting, keep track of them, and put them back where they "belong". However, the only mechanism it has to decide where it "belongs" is the line it was at originally. This can easily change based on what the formatter ended up changing. This means that the only way this fix predictably and reliably works is for directives that are at the top of the document before the document actually starts (i.e. where the `%YAML` directive goes).
102+
103+
In addition, while with this feature the `%YAML` directive may work, the formatter very specifically supports only the [YAML 1.2 spec](https://yaml.org/spec/1.2.2/). So the `%YAML:1.0` directive won't have the desired effect when passing a file through `yamlfmt`, and if you have 1.0-only syntax in your document the formatter may end up failing in other ways that will be unfixable.
104+
92105
[1]: https://www.github.com/braydonk/yaml
93106
[Specifying Paths]: ./paths.md

feature.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414

1515
package yamlfmt
1616

17-
import "fmt"
17+
import (
18+
"context"
19+
"fmt"
20+
)
1821

19-
type FeatureFunc func([]byte) ([]byte, error)
22+
type FeatureFunc func(context.Context, []byte) (context.Context, []byte, error)
2023

2124
type Feature struct {
2225
Name string
@@ -47,29 +50,29 @@ func (e *FeatureApplyError) Unwrap() error {
4750
return e.err
4851
}
4952

50-
func (fl FeatureList) ApplyFeatures(input []byte, mode FeatureApplyMode) ([]byte, error) {
53+
func (fl FeatureList) ApplyFeatures(ctx context.Context, input []byte, mode FeatureApplyMode) (context.Context, []byte, error) {
5154
// Declare err here so the result variable doesn't get shadowed in the loop
5255
var err error
5356
result := make([]byte, len(input))
5457
copy(result, input)
5558
for _, feature := range fl {
5659
if mode == FeatureApplyBefore {
5760
if feature.BeforeAction != nil {
58-
result, err = feature.BeforeAction(result)
61+
ctx, result, err = feature.BeforeAction(ctx, result)
5962
}
6063
} else {
6164
if feature.AfterAction != nil {
62-
result, err = feature.AfterAction(result)
65+
ctx, result, err = feature.AfterAction(ctx, result)
6366
}
6467
}
6568

6669
if err != nil {
67-
return nil, &FeatureApplyError{
70+
return ctx, nil, &FeatureApplyError{
6871
err: err,
6972
featureName: feature.Name,
7073
mode: mode,
7174
}
7275
}
7376
}
74-
return result, nil
77+
return ctx, result, nil
7578
}

formatters/basic/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Config struct {
3434
PadLineComments int `mapstructure:"pad_line_comments"`
3535
TrimTrailingWhitespace bool `mapstructure:"trim_trailing_whitespace"`
3636
EOFNewline bool `mapstructure:"eof_newline"`
37+
StripDirectives bool `mapstructure:"strip_directives"`
3738
}
3839

3940
func DefaultConfig() *Config {

formatters/basic/features.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ func ConfigureFeaturesFromConfig(config *Config) yamlfmt.FeatureList {
4646
features.MakeFeatureEOFNewline(lineSep),
4747
)
4848
}
49+
if config.StripDirectives {
50+
configuredFeatures = append(
51+
configuredFeatures,
52+
hotfix.MakeFeatureStripDirectives(lineSep),
53+
)
54+
}
4955
return configuredFeatures
5056
}
5157

formatters/basic/formatter.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package basic
1616

1717
import (
1818
"bytes"
19+
"context"
1920
"errors"
2021
"io"
2122

@@ -40,7 +41,8 @@ func (f *BasicFormatter) Type() string {
4041

4142
func (f *BasicFormatter) Format(input []byte) ([]byte, error) {
4243
// Run all features with BeforeActions
43-
yamlContent, err := f.Features.ApplyFeatures(input, yamlfmt.FeatureApplyBefore)
44+
ctx := context.Background()
45+
ctx, yamlContent, err := f.Features.ApplyFeatures(ctx, input, yamlfmt.FeatureApplyBefore)
4446
if err != nil {
4547
return nil, err
4648
}
@@ -78,7 +80,7 @@ func (f *BasicFormatter) Format(input []byte) ([]byte, error) {
7880
}
7981

8082
// Run all features with AfterActions
81-
resultYaml, err := f.Features.ApplyFeatures(b.Bytes(), yamlfmt.FeatureApplyAfter)
83+
_, resultYaml, err := f.Features.ApplyFeatures(ctx, b.Bytes(), yamlfmt.FeatureApplyAfter)
8284
if err != nil {
8385
return nil, err
8486
}

formatters/basic/formatter_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/google/yamlfmt"
2222
"github.com/google/yamlfmt/formatters/basic"
23+
"github.com/google/yamlfmt/internal/assert"
2324
)
2425

2526
func newFormatter(config *basic.Config) *basic.BasicFormatter {
@@ -351,3 +352,14 @@ b: 2
351352
t.Fatalf("expected: '%s', got: '%s'", expectedYml, resultStr)
352353
}
353354
}
355+
356+
func TestStripDirectives(t *testing.T) {
357+
config := basic.DefaultConfig()
358+
config.StripDirectives = true
359+
f := newFormatter(config)
360+
361+
yml := "%YAML:1.0"
362+
363+
_, err := f.Format([]byte(yml))
364+
assert.NilErr(t, err)
365+
}

integrationtest/command/command_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,11 @@ func TestEOFNewline(t *testing.T) {
139139
Update: *updateFlag,
140140
}.Run(t)
141141
}
142+
143+
func TestStripDirectives(t *testing.T) {
144+
TestCase{
145+
Dir: "strip_directives",
146+
Command: yamlfmtWithArgs("-formatter strip_directives=true ."),
147+
Update: *updateFlag,
148+
}.Run(t)
149+
}

integrationtest/command/testdata/print_conf_file/stdout/stdout.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ formatter:
2424
retain_line_breaks: false
2525
retain_line_breaks_single: true
2626
scan_folded_as_literal: false
27+
strip_directives: false
2728
trim_trailing_whitespace: false
2829
type: basic

integrationtest/command/testdata/print_conf_flags/stdout/stdout.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ formatter:
2323
retain_line_breaks: true
2424
retain_line_breaks_single: false
2525
scan_folded_as_literal: false
26+
strip_directives: false
2627
trim_trailing_whitespace: false
2728
type: basic

integrationtest/command/testdata/print_conf_flags_and_file/stdout/stdout.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ formatter:
2424
retain_line_breaks: true
2525
retain_line_breaks_single: true
2626
scan_folded_as_literal: false
27+
strip_directives: false
2728
trim_trailing_whitespace: false
2829
type: basic

0 commit comments

Comments
 (0)