mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
feat(common): Add string parser
This commit is contained in:
parent
f530195cac
commit
eb587dfb42
129
common/parser/strings.go
Normal file
129
common/parser/strings.go
Normal file
@ -0,0 +1,129 @@
|
||||
package parser
|
||||
|
||||
type ParseFeatures struct {
|
||||
ParseDoubleQuotes bool
|
||||
ParseEscapedCharacters bool
|
||||
}
|
||||
|
||||
var FullFeatures = ParseFeatures{
|
||||
ParseDoubleQuotes: true,
|
||||
ParseEscapedCharacters: true,
|
||||
}
|
||||
|
||||
type ParsedString struct {
|
||||
Raw string
|
||||
Value string
|
||||
|
||||
Features ParseFeatures
|
||||
}
|
||||
|
||||
func ParseRawString(
|
||||
raw string,
|
||||
features ParseFeatures,
|
||||
) ParsedString {
|
||||
value := raw
|
||||
|
||||
// Parse double quotes
|
||||
if features.ParseDoubleQuotes {
|
||||
value = ParseDoubleQuotes(value)
|
||||
}
|
||||
|
||||
// Parse escaped characters
|
||||
if features.ParseEscapedCharacters {
|
||||
value = ParseEscapedCharacters(value)
|
||||
}
|
||||
|
||||
return ParsedString{
|
||||
Raw: raw,
|
||||
Value: value,
|
||||
Features: features,
|
||||
}
|
||||
}
|
||||
|
||||
func ParseDoubleQuotes(
|
||||
raw string,
|
||||
) string {
|
||||
value := raw
|
||||
currentIndex := 0
|
||||
|
||||
for {
|
||||
start, found := findNextDoubleQuote(value, currentIndex)
|
||||
|
||||
if found && start < (len(value)-1) {
|
||||
currentIndex = max(0, start-1)
|
||||
end, found := findNextDoubleQuote(value, start+1)
|
||||
|
||||
if found {
|
||||
insideContent := value[start+1 : end]
|
||||
value = modifyString(value, start, end+1, insideContent)
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func ParseEscapedCharacters(
|
||||
raw string,
|
||||
) string {
|
||||
value := raw
|
||||
currentIndex := 0
|
||||
|
||||
for {
|
||||
position, found := findNextEscapedCharacter(value, currentIndex)
|
||||
|
||||
if found {
|
||||
currentIndex = max(0, position-1)
|
||||
escapedCharacter := value[position+1]
|
||||
value = modifyString(value, position, position+2, string(escapedCharacter))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func modifyString(
|
||||
input string,
|
||||
start int,
|
||||
end int,
|
||||
newValue string,
|
||||
) string {
|
||||
return input[:start] + newValue + input[end:]
|
||||
}
|
||||
|
||||
// Find the next non-escaped double quote in [raw] starting from [startIndex]
|
||||
// When no double quote is found, return -1
|
||||
// Return as the second argument whether a double quote was found
|
||||
func findNextDoubleQuote(
|
||||
raw string,
|
||||
startIndex int,
|
||||
) (int, bool) {
|
||||
for index := startIndex; index < len(raw); index++ {
|
||||
if raw[index] == '"' {
|
||||
if index == 0 || raw[index-1] != '\\' {
|
||||
return index, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func findNextEscapedCharacter(
|
||||
raw string,
|
||||
startIndex int,
|
||||
) (int, bool) {
|
||||
for index := startIndex; index < len(raw); index++ {
|
||||
if raw[index] == '\\' && index < len(raw)-1 {
|
||||
return index, true
|
||||
}
|
||||
}
|
||||
|
||||
return -1, false
|
||||
}
|
177
common/parser/strings_test.go
Normal file
177
common/parser/strings_test.go
Normal file
@ -0,0 +1,177 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestStringsSingleWortQuotedFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world"`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: "hello world",
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsFullyQuotedFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `"hello world"`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: "hello world",
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsMultipleQuotesFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world goodbye"`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: "hello world goodbye",
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsSimpleEscapedFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello \"world`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello "world`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsEscapedQuotesFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello \"world\"`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello "world"`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsQuotesAndEscapedFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world how\" are you"`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello world how" are you`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsIncompleteQuotesFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello "world`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsIncompleteQuoteEscapedFullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world\"`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello "world"`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsIncompleteQuotes2FullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world how" "are you`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello world how "are you`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringsIncompleteQuotes3FullFeatures(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := `hello "world how are you`
|
||||
expected := ParsedString{
|
||||
Raw: input,
|
||||
Value: `hello "world how are you`,
|
||||
Features: FullFeatures,
|
||||
}
|
||||
|
||||
actual := ParseRawString(input, FullFeatures)
|
||||
|
||||
if !(cmp.Equal(expected, actual)) {
|
||||
t.Errorf("Expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
1
go.mod
1
go.mod
@ -11,6 +11,7 @@ require (
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||
github.com/k0kubun/pp v3.0.1+incompatible // indirect
|
||||
|
2
go.sum
2
go.sum
@ -4,6 +4,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
|
Loading…
x
Reference in New Issue
Block a user