mirror of
https://github.com/jimeh/undent.git
synced 2026-02-19 11:56:39 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
4ded03bd72
|
|||
| 68a97519d5 | |||
|
5dbdbbf341
|
|||
|
d79e413e8e
|
|||
| cc372da881 | |||
|
b2057429a1
|
|||
|
24e64f6c39
|
|||
|
30dba69951
|
14
CHANGELOG.md
14
CHANGELOG.md
@@ -2,6 +2,20 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [1.0.2](https://github.com/jimeh/undent/compare/v1.0.1...v1.0.2) (2020-12-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bytes:** change Bytes function to accept string input but return a byte slice ([5dbdbbf](https://github.com/jimeh/undent/commit/5dbdbbf3416b024aac8fca4e218802d6ad49ea74))
|
||||
|
||||
### [1.0.1](https://github.com/jimeh/undent/compare/v1.0.0...v1.0.1) (2020-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **whitespace:** remove leading line-break from input ([b205742](https://github.com/jimeh/undent/commit/b2057429a1181724ae50acaed26fe434231362b4))
|
||||
|
||||
## 1.0.0 (2020-11-26)
|
||||
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -4,8 +4,8 @@
|
||||
|
||||
<p align="center">
|
||||
<strong>
|
||||
Go package which removes leading indentation/white-space from multi-line
|
||||
strings and byte slices.
|
||||
Go package which removes leading indentation/white-space from strings and
|
||||
byte slices.
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
@@ -52,8 +52,14 @@ fmt.Println(s)
|
||||
|
||||
## Documentation
|
||||
|
||||
Please see the [Go Reference](https://pkg.go.dev/github.com/jimeh/undent) for
|
||||
documentation and examples.
|
||||
Please see the
|
||||
[Go Reference](https://pkg.go.dev/github.com/jimeh/undent#section-documentation)
|
||||
for documentation and examples.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Benchmark reports and graphs are available here:
|
||||
https://jimeh.me/undent/dev/bench/
|
||||
|
||||
## License
|
||||
|
||||
|
||||
39
undent.go
39
undent.go
@@ -9,36 +9,25 @@ import (
|
||||
|
||||
var matcher = regexp.MustCompile(`(?m)^([ \t]*)(?:\S)`)
|
||||
|
||||
// Bytes removes leading indentation/white-space from given byte slice.
|
||||
func Bytes(b []byte) []byte {
|
||||
matches := matcher.FindAll(b, -1)
|
||||
if len(matches) == 0 {
|
||||
return b
|
||||
}
|
||||
// Bytes removes leading indentation/white-space from given string and returns
|
||||
// it as a byte slice.
|
||||
func Bytes(s string) []byte {
|
||||
return []byte(String(s))
|
||||
}
|
||||
|
||||
index := 0
|
||||
length := len(matches[0])
|
||||
|
||||
for i, s := range matches[1:] {
|
||||
l := len(s)
|
||||
if l < length {
|
||||
index = i + 1
|
||||
length = l
|
||||
}
|
||||
}
|
||||
|
||||
if length <= 1 {
|
||||
return b
|
||||
}
|
||||
indent := matches[index][0 : length-1]
|
||||
|
||||
return regexp.MustCompile(
|
||||
`(?m)^`+regexp.QuoteMeta(string(indent)),
|
||||
).ReplaceAllLiteral(b, []byte{})
|
||||
// Bytesf removes leading indentation/white-space from given format string
|
||||
// before passing format and all additional arguments to fmt.Sprintf, returning
|
||||
// the result as a byte slice.
|
||||
func Bytesf(format string, a ...interface{}) []byte {
|
||||
return []byte(Stringf(format, a...))
|
||||
}
|
||||
|
||||
// String removes leading indentation/white-space from given string.
|
||||
func String(s string) string {
|
||||
if len(s) > 0 && s[0] == '\n' {
|
||||
s = s[1:]
|
||||
}
|
||||
|
||||
matches := matcher.FindAllString(s, -1)
|
||||
if len(matches) == 0 {
|
||||
return s
|
||||
|
||||
@@ -7,15 +7,28 @@ import (
|
||||
)
|
||||
|
||||
func ExampleBytes() {
|
||||
b := undent.Bytes([]byte(`
|
||||
b := undent.Bytes(`
|
||||
{
|
||||
"hello": "world"
|
||||
}`,
|
||||
))
|
||||
)
|
||||
|
||||
fmt.Println(string(b))
|
||||
// Output:
|
||||
//
|
||||
// {
|
||||
// "hello": "world"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleBytesf() {
|
||||
s := undent.Bytesf(`
|
||||
{
|
||||
"hello": "%s"
|
||||
}`,
|
||||
"world",
|
||||
)
|
||||
fmt.Println(string(s))
|
||||
// Output:
|
||||
// {
|
||||
// "hello": "world"
|
||||
// }
|
||||
@@ -29,7 +42,6 @@ func ExampleString() {
|
||||
)
|
||||
fmt.Println(s)
|
||||
// Output:
|
||||
//
|
||||
// {
|
||||
// "hello": "world"
|
||||
// }
|
||||
@@ -44,7 +56,6 @@ func ExampleStringf() {
|
||||
)
|
||||
fmt.Println(s)
|
||||
// Output:
|
||||
//
|
||||
// {
|
||||
// "hello": "world"
|
||||
// }
|
||||
|
||||
136
undent_test.go
136
undent_test.go
@@ -35,8 +35,7 @@ var stringTestCases = []struct {
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
@@ -46,6 +45,24 @@ var stringTestCases = []struct {
|
||||
{
|
||||
name: "multi-line space indented",
|
||||
s: `
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line space indented with leading line-breaks",
|
||||
s: `
|
||||
|
||||
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
@@ -53,6 +70,7 @@ var stringTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
want: `
|
||||
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
@@ -63,6 +81,24 @@ var stringTestCases = []struct {
|
||||
{
|
||||
name: "multi-line tab indented",
|
||||
s: `
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line tab indented with leading line breaks",
|
||||
s: `
|
||||
|
||||
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
@@ -70,6 +106,7 @@ var stringTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
want: `
|
||||
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
@@ -86,8 +123,7 @@ var stringTestCases = []struct {
|
||||
"bar"
|
||||
]
|
||||
}`,
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
"bar"
|
||||
@@ -105,8 +141,7 @@ var stringTestCases = []struct {
|
||||
|
||||
]
|
||||
}`,
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
|
||||
@@ -126,8 +161,7 @@ var stringTestCases = []struct {
|
||||
|
||||
]
|
||||
}`,
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
|
||||
@@ -143,8 +177,7 @@ var stringTestCases = []struct {
|
||||
world
|
||||
foo
|
||||
bar`,
|
||||
want: `
|
||||
hello
|
||||
want: ` hello
|
||||
world
|
||||
foo
|
||||
bar`,
|
||||
@@ -156,8 +189,7 @@ world
|
||||
world
|
||||
foo
|
||||
bar`,
|
||||
want: `
|
||||
hello
|
||||
want: ` hello
|
||||
world
|
||||
foo
|
||||
bar`,
|
||||
@@ -197,8 +229,7 @@ var stringfTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
42
|
||||
@@ -208,6 +239,25 @@ var stringfTestCases = []struct {
|
||||
{
|
||||
name: "multi-line space indented",
|
||||
s: `
|
||||
{
|
||||
"hello": "%s",
|
||||
"foo": [
|
||||
%d
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
42
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line space indented with leading line-breaks",
|
||||
s: `
|
||||
|
||||
|
||||
{
|
||||
"hello": "%s",
|
||||
"foo": [
|
||||
@@ -216,6 +266,7 @@ var stringfTestCases = []struct {
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
@@ -233,7 +284,27 @@ var stringfTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
42
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "multi-line tab indented with leading line-breaks",
|
||||
s: `
|
||||
|
||||
|
||||
{
|
||||
"hello": "%s",
|
||||
"foo": [
|
||||
%d
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
|
||||
{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
@@ -251,8 +322,7 @@ var stringfTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
42
|
||||
@@ -271,8 +341,7 @@ var stringfTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
|
||||
@@ -293,8 +362,7 @@ var stringfTestCases = []struct {
|
||||
]
|
||||
}`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
{
|
||||
want: `{
|
||||
"hello": "world",
|
||||
"foo": [
|
||||
|
||||
@@ -311,8 +379,7 @@ var stringfTestCases = []struct {
|
||||
foo
|
||||
%d`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
hello
|
||||
want: ` hello
|
||||
world
|
||||
foo
|
||||
42`,
|
||||
@@ -325,8 +392,7 @@ world
|
||||
foo
|
||||
%d`,
|
||||
a: []interface{}{"world", 42},
|
||||
want: `
|
||||
hello
|
||||
want: ` hello
|
||||
world
|
||||
foo
|
||||
42`,
|
||||
@@ -336,9 +402,21 @@ world
|
||||
func TestBytes(t *testing.T) {
|
||||
for _, tt := range stringTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Bytes([]byte(tt.s))
|
||||
got := Bytes(tt.s)
|
||||
|
||||
assert.Equal(t, []byte(tt.want), got)
|
||||
assert.IsType(t, []byte{}, got)
|
||||
assert.Equal(t, tt.want, string(got))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesf(t *testing.T) {
|
||||
for _, tt := range stringfTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Bytesf(tt.s, tt.a...)
|
||||
|
||||
assert.IsType(t, []byte{}, got)
|
||||
assert.Equal(t, tt.want, string(got))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -348,6 +426,7 @@ func TestString(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := String(tt.s)
|
||||
|
||||
assert.IsType(t, "", got)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
@@ -358,6 +437,7 @@ func TestStringf(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Stringf(tt.s, tt.a...)
|
||||
|
||||
assert.IsType(t, "", got)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
@@ -366,10 +446,8 @@ func TestStringf(t *testing.T) {
|
||||
func BenchmarkBytes(b *testing.B) {
|
||||
for _, tt := range stringTestCases {
|
||||
b.Run(tt.name, func(b *testing.B) {
|
||||
input := []byte(tt.s)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Bytes(input)
|
||||
Bytes(tt.s)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user