Skip to content

Commit 31595a9

Browse files
committed
initial commit
0 parents  commit 31595a9

File tree

7 files changed

+207
-0
lines changed

7 files changed

+207
-0
lines changed

.github/workflows/build.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# https://github.com/marketplace/actions/go-release-binaries
2+
name: Release CI
3+
4+
on:
5+
release:
6+
types: [created]
7+
8+
jobs:
9+
release-builds:
10+
name: release linux/amd64
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
goos: [linux,windows,darwin]
15+
goarch: [amd64, arm64]
16+
exclude:
17+
- goarch: arm64
18+
goos: windows
19+
steps:
20+
- uses: actions/checkout@v2
21+
- uses: wangyoucao577/go-release-action@v1.53
22+
with:
23+
github_token: ${{ secrets.GITHUB_TOKEN }}
24+
goversion: "https://dl.google.com/go/go1.24.2.linux-amd64.tar.gz"
25+
goos: ${{ matrix.goos }}
26+
goarch: ${{ matrix.goarch }}
27+
binary_name: jsonlint
28+
retry: 10
29+
sha256sum: true
30+
md5sum: false
31+
overwrite: true
32+
pre_command: go mod tidy

.github/workflows/coverage.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: "Go Coverage"
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
# It's important that the action also runs on merge to main
7+
- main
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
name: Update coverage badge
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
with:
16+
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
17+
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
18+
19+
- name: Setup go
20+
uses: actions/setup-go@v4
21+
with:
22+
go-version-file: 'go.mod'
23+
24+
- name: Run Test
25+
run: |
26+
go test -v ./... -covermode=count -coverprofile=coverage.out
27+
go tool cover -func=coverage.out -o=coverage.out
28+
29+
- name: Go Coverage Badge # Pass the `coverage.out` output to this action
30+
uses: tj-actions/coverage-badge-go@v2
31+
with:
32+
filename: coverage.out
33+
34+
- name: Verify Changed files
35+
uses: tj-actions/verify-changed-files@v17
36+
id: verify-changed-files
37+
with:
38+
files: README.md
39+
40+
- name: Commit changes
41+
if: steps.verify-changed-files.outputs.files_changed == 'true'
42+
run: |
43+
git config --local user.email "action@github.com"
44+
git config --local user.name "GitHub Action"
45+
git add README.md
46+
git commit -m "chore: Updated coverage badge."
47+
48+
- name: Push changes
49+
if: steps.verify-changed-files.outputs.files_changed == 'true'
50+
uses: ad-m/github-push-action@master
51+
with:
52+
github_token: ${{ github.token }}
53+
branch: ${{ github.head_ref }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
jsonlint

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# jsonlint
2+
3+
A small linter for json files

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module main.go
2+
3+
go 1.24.4

main.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"os"
9+
)
10+
11+
func main() {
12+
err := LintJSON(os.Stdin, os.Stdout)
13+
if err != nil {
14+
fmt.Fprintln(os.Stderr, err)
15+
os.Exit(1)
16+
}
17+
}
18+
19+
// LintJSON reads from input, parses JSON, writes formatted JSON to output,
20+
// and returns error with line/column info if parsing fails.
21+
func LintJSON(input io.Reader, output io.Writer) error {
22+
reader := bufio.NewReader(input)
23+
var data map[string]interface{}
24+
25+
var inputBuffer []byte
26+
tee := io.TeeReader(reader, &bufferWriter{&inputBuffer})
27+
28+
decoder := json.NewDecoder(tee)
29+
err := decoder.Decode(&data)
30+
if err != nil {
31+
offset := decoder.InputOffset()
32+
line, col := getLineAndColumn(inputBuffer, offset)
33+
return fmt.Errorf("JSON parse error at line %d, column %d: %v", line, col, err)
34+
}
35+
36+
encoder := json.NewEncoder(output)
37+
encoder.SetEscapeHTML(false)
38+
encoder.SetIndent("", " ")
39+
err = encoder.Encode(data)
40+
if err != nil {
41+
return fmt.Errorf("JSON encoding error: %v", err)
42+
}
43+
return nil
44+
}
45+
46+
type bufferWriter struct {
47+
buf *[]byte
48+
}
49+
50+
func (bw *bufferWriter) Write(p []byte) (int, error) {
51+
*bw.buf = append(*bw.buf, p...)
52+
return len(p), nil
53+
}
54+
55+
func getLineAndColumn(data []byte, offset int64) (line, column int) {
56+
line = 1
57+
column = 1
58+
for i := int64(0); i < offset && i < int64(len(data)); i++ {
59+
if data[i] == '\n' {
60+
line++
61+
column = 1
62+
} else {
63+
column++
64+
}
65+
}
66+
return
67+
}
68+

main_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
)
8+
9+
func TestLintJSON_Valid(t *testing.T) {
10+
input := `{
11+
"name": "ChatGPT",
12+
"language": "Go",
13+
"version": 4
14+
}`
15+
var output bytes.Buffer
16+
err := LintJSON(strings.NewReader(input), &output)
17+
if err != nil {
18+
t.Errorf("Expected valid JSON, got error: %v", err)
19+
}
20+
if !strings.Contains(output.String(), `"name": "ChatGPT"`) {
21+
t.Errorf("Output JSON missing expected content: %s", output.String())
22+
}
23+
}
24+
25+
func TestLintJSON_Invalid(t *testing.T) {
26+
input := `{
27+
"name": "ChatGPT",
28+
"skills": ["Go", "Python"
29+
}` // Missing closing bracket
30+
31+
var output bytes.Buffer
32+
err := LintJSON(strings.NewReader(input), &output)
33+
if err == nil {
34+
t.Error("Expected error for malformed JSON, got nil")
35+
} else if !strings.Contains(err.Error(), "line 4") {
36+
t.Errorf("Expected error to mention line number, got: %v", err)
37+
}
38+
}
39+
40+
func TestLintJSON_Empty(t *testing.T) {
41+
var output bytes.Buffer
42+
err := LintJSON(strings.NewReader(""), &output)
43+
if err == nil {
44+
t.Error("Expected error for empty input, got nil")
45+
}
46+
}
47+

0 commit comments

Comments
 (0)