mirror of
https://github.com/mikefarah/yq.git
synced 2026-07-04 11:25:37 +00:00
Merge remote-tracking branch 'origin/pr/2552' into copilot/sub-pr-2552
# Conflicts: # pkg/yqlib/toml_test.go
This commit is contained in:
commit
1de4ec59f2
@ -4,7 +4,7 @@
|
|||||||
- run ./scripts/format.sh then ./scripts/check.sh to format, then validate linting and spelling
|
- run ./scripts/format.sh then ./scripts/check.sh to format, then validate linting and spelling
|
||||||
- Add comprehensive tests to cover the changes
|
- Add comprehensive tests to cover the changes
|
||||||
- Run test suite to ensure there is no regression
|
- Run test suite to ensure there is no regression
|
||||||
|
- Use UK english spelling (e.g. Colorisation not Colorization)
|
||||||
|
|
||||||
❌ **DON'T:**
|
❌ **DON'T:**
|
||||||
- Git add or commit
|
- Git add or commit
|
||||||
|
|||||||
@ -466,9 +466,7 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Preserve EncodeSeparate flag for format-specific encoding hints
|
// Preserve EncodeSeparate flag for format-specific encoding hints
|
||||||
if other.EncodeSeparate {
|
n.EncodeSeparate = other.EncodeSeparate
|
||||||
n.EncodeSeparate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge will pickup the style of the new thing
|
// merge will pickup the style of the new thing
|
||||||
// when autocreating nodes
|
// when autocreating nodes
|
||||||
|
|||||||
@ -34,10 +34,9 @@ func (te *tomlEncoder) Encode(writer io.Writer, node *CandidateNode) error {
|
|||||||
// Encode to a buffer first if colors are enabled
|
// Encode to a buffer first if colors are enabled
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
var targetWriter io.Writer
|
var targetWriter io.Writer
|
||||||
|
targetWriter = writer
|
||||||
if te.prefs.ColorsEnabled {
|
if te.prefs.ColorsEnabled {
|
||||||
targetWriter = &buf
|
targetWriter = &buf
|
||||||
} else {
|
|
||||||
targetWriter = writer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode a root mapping as a sequence of attributes, tables, and arrays of tables
|
// Encode a root mapping as a sequence of attributes, tables, and arrays of tables
|
||||||
@ -635,8 +634,16 @@ func (te *tomlEncoder) colorizeToml(input []byte) []byte {
|
|||||||
if ch == '-' {
|
if ch == '-' {
|
||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
for end < len(toml) && ((toml[end] >= '0' && toml[end] <= '9') || toml[end] == '.' || toml[end] == 'e' || toml[end] == 'E' || toml[end] == '+' || toml[end] == '-') {
|
for end < len(toml) {
|
||||||
end++
|
c := toml[end]
|
||||||
|
if (c >= '0' && c <= '9') || c == '.' || c == 'e' || c == 'E' {
|
||||||
|
end++
|
||||||
|
} else if (c == '+' || c == '-') && end > 0 && (toml[end-1] == 'e' || toml[end-1] == 'E') {
|
||||||
|
// Only allow + or - immediately after 'e' or 'E' for scientific notation
|
||||||
|
end++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.WriteString(numberColor(toml[i:end]))
|
result.WriteString(numberColor(toml[i:end]))
|
||||||
i = end
|
i = end
|
||||||
|
|||||||
@ -685,3 +685,114 @@ alpha = "test"
|
|||||||
t.Errorf("Expected section colour to appear exactly 2 times (for [database] and [servers]), but it appeared %d times.\nOutput: %s", sectionColourCount, resultStr)
|
t.Errorf("Expected section colour to appear exactly 2 times (for [database] and [servers]), but it appeared %d times.\nOutput: %s", sectionColourCount, resultStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTomlColorisationNumberBug(t *testing.T) {
|
||||||
|
// Save and restore color state
|
||||||
|
oldNoColor := color.NoColor
|
||||||
|
color.NoColor = false
|
||||||
|
defer func() { color.NoColor = oldNoColor }()
|
||||||
|
|
||||||
|
encoder := NewTomlEncoder()
|
||||||
|
tomlEncoder := encoder.(*tomlEncoder)
|
||||||
|
|
||||||
|
// Test case that exposes the bug: "123-+-45" should NOT be colorized as a single number
|
||||||
|
input := "A = 123-+-45\n"
|
||||||
|
result := string(tomlEncoder.colorizeToml([]byte(input)))
|
||||||
|
|
||||||
|
// The bug causes "123-+-45" to be colorized as one token
|
||||||
|
// It should stop at "123" because the next character '-' is not valid in this position
|
||||||
|
if strings.Contains(result, "123-+-45") {
|
||||||
|
// Check if it's colorized as a single token (no color codes in the middle)
|
||||||
|
idx := strings.Index(result, "123-+-45")
|
||||||
|
// Look backwards for color code
|
||||||
|
beforeIdx := idx - 1
|
||||||
|
for beforeIdx >= 0 && result[beforeIdx] != '\x1b' {
|
||||||
|
beforeIdx--
|
||||||
|
}
|
||||||
|
// Look forward for reset code
|
||||||
|
afterIdx := idx + 8 // length of "123-+-45"
|
||||||
|
hasResetAfter := false
|
||||||
|
for afterIdx < len(result) && afterIdx < idx+20 {
|
||||||
|
if result[afterIdx] == '\x1b' {
|
||||||
|
hasResetAfter = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
afterIdx++
|
||||||
|
}
|
||||||
|
|
||||||
|
if beforeIdx >= 0 && hasResetAfter {
|
||||||
|
// The entire "123-+-45" is wrapped in color codes - this is the bug!
|
||||||
|
t.Errorf("BUG DETECTED: '123-+-45' is incorrectly colorized as a single number")
|
||||||
|
t.Errorf("Expected only '123' to be colorized as a number, but got the entire '123-+-45'")
|
||||||
|
t.Logf("Full output: %q", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional test cases for the bug
|
||||||
|
bugTests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
invalidSequence string
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "consecutive minuses",
|
||||||
|
input: "A = 123--45\n",
|
||||||
|
invalidSequence: "123--45",
|
||||||
|
description: "'123--45' should not be colorized as a single number",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "plus in middle",
|
||||||
|
input: "A = 123+45\n",
|
||||||
|
invalidSequence: "123+45",
|
||||||
|
description: "'123+45' should not be colorized as a single number",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range bugTests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := string(tomlEncoder.colorizeToml([]byte(tt.input)))
|
||||||
|
if strings.Contains(result, tt.invalidSequence) {
|
||||||
|
idx := strings.Index(result, tt.invalidSequence)
|
||||||
|
beforeIdx := idx - 1
|
||||||
|
for beforeIdx >= 0 && result[beforeIdx] != '\x1b' {
|
||||||
|
beforeIdx--
|
||||||
|
}
|
||||||
|
afterIdx := idx + len(tt.invalidSequence)
|
||||||
|
hasResetAfter := false
|
||||||
|
for afterIdx < len(result) && afterIdx < idx+20 {
|
||||||
|
if result[afterIdx] == '\x1b' {
|
||||||
|
hasResetAfter = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
afterIdx++
|
||||||
|
}
|
||||||
|
|
||||||
|
if beforeIdx >= 0 && hasResetAfter {
|
||||||
|
t.Errorf("BUG: %s", tt.description)
|
||||||
|
t.Logf("Full output: %q", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that valid scientific notation still works
|
||||||
|
validTests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
}{
|
||||||
|
{"scientific positive", "A = 1.23e+45\n"},
|
||||||
|
{"scientific negative", "A = 6.626e-34\n"},
|
||||||
|
{"scientific uppercase", "A = 1.23E+10\n"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range validTests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := tomlEncoder.colorizeToml([]byte(tt.input))
|
||||||
|
if len(result) == 0 {
|
||||||
|
t.Error("Expected non-empty colorized output")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user