diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..49b34aa
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+
+[*.go]
+indent_style = tab
+insert_final_newline = false
+
+[Makefile]
+indent_style = tab
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..28fa3a8
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,24 @@
+name: Build
+
+on:
+ push:
+ branches:
+ - main
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up env
+ run: |
+ VERSION=${GITHUB_REF_NAME#v}
+ echo "VERSION=$VERSION" >> $GITHUB_ENV
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: 1.22
+ - name: Build
+ run: make builds
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 0000000..7799943
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,35 @@
+name: Lint
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+permissions:
+ contents: read
+ pull-requests: read
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up env
+ run: |
+ VERSION=${GITHUB_REF_NAME#v}
+ echo "VERSION=$VERSION" >> $GITHUB_ENV
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: 1.22
+ - name: Set up golangci-lint
+ uses: golangci/golangci-lint-action@v6
+ with:
+ version: v1.58
+ cache: true
+ - name: Lint
+ run: make lint
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..52fd537
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,29 @@
+name: Release
+
+on:
+ push:
+ tags:
+ - 'v[0-9]+.[0-9]+.[0-9]+'
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up env
+ run: |
+ VERSION=${GITHUB_REF_NAME#v}
+ echo "VERSION=$VERSION" >> $GITHUB_ENV
+ - name: Set up Go
+ uses: actions/setup-go@v2
+ with:
+ go-version: 1.22
+ cache: true
+ - name: Build
+ run: make builds
+ - name: Release
+ run: make release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..f5a5a68
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,31 @@
+name: Test
+
+on:
+ push:
+ branches:
+ - main
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up env
+ run: |
+ VERSION=${GITHUB_REF_NAME#v}
+ echo "VERSION=$VERSION" >> $GITHUB_ENV
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: 1.22
+ - name: Test
+ run: make test-coverage
+ - name: Upload to Codecov
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ fail_ci_if_error: true
+ files: ./coverage.out
+ name: codecov-umbrella
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..839f065
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Go workspace file
+go.work
+
+/configurations
+/shazam.yml
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dc19184
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 mistweaver.co
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fd07d31
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+BIN_NAME=kulala-fmt
+
+build-windows-64:
+ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w -X 'github.com/mistweaverco/kulala-fmt/cmd/kulalafmt.VERSION=$(VERSION)'" -o dist/windows/$(BIN_NAME).exe main.go
+build-linux-64:
+ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w -X 'github.com/mistweaverco/kulala-fmt/cmd/kulalafmt.VERSION=$(VERSION)'" -o dist/linux/$(BIN_NAME)-linux main.go
+build-macos-arm64:
+ GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags "-s -w -X 'github.com/mistweaverco/kulala-fmt/cmd/kulalafmt.VERSION=$(VERSION)'" -o dist/macos/$(BIN_NAME)-macos main.go
+
+builds: build-linux-64 build-macos-arm64 build-windows-64
+
+lint:
+ golangci-lint run
+
+test:
+ if [ -n $(COLORS_ENABLED) ]; then gotest ./... ; else go test ./...; fi
+
+test-coverage:
+ go test -race -covermode=atomic -coverprofile=coverage.out ./...
+
+release:
+ gh release create --generate-notes v$(VERSION) dist/linux/$(BIN_NAME)-linux dist/macos/$(BIN_NAME)-macos dist/windows/$(BIN_NAME).exe
+
+build-and-install-local-debug:
+ go build -ldflags "-X 'github.com/mistweaverco/kulala-fmt/cmd/kulalafmt.VERSION=development'" -o dist/$(BIN_NAME) main.go
+ sudo mv dist/$(BIN_NAME) /usr/bin/$(BIN_NAME)
+
+run:
+ go run -ldflags "-X 'github.com/mistweaverco/kulala-fmt/cmd/kulalafmt.VERSION=development'" main.go
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9094de1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+
+
+
+
+# kulala-fmt
+
+[](https://golang.org)
+[](/~https://github.com/mistweaverco/kulala-fmt/releases/latest)
+[](https://discord.gg/QyVQmfY4Rt)
+
+[Install](#install) • [Usage](#usage)
+
+
+
+An opinionated 🦄 .http and .rest 🐼 files linter 💄 and formatter ⚡.
+
+
+
+
+
+## Install
+
+Just grab the latest release:
+
+ - [Linux](/~https://github.com/mistweaverco/kulala-fmt/releases/download/latest/kulala-fmt-linux)
+ - [Mac](/~https://github.com/mistweaverco/kulala-fmt/releases/download/latest/kulala-fmt-macos)
+ - [Windows](/~https://github.com/mistweaverco/kulala-fmt/releases/download/latest/kulala-fmt.exe)
+
+## Usage
+
+Format all `.http` and `.rest` files in the current directory and its subdirectories:
+
+```sh
+kulala-fmt
+```
+
+Check if all `.http` and `.rest` files in the current directory and its subdirectories are formatted:
+
+```sh
+kulala-fmt --check
+```
diff --git a/cmd/kulalafmt/about.go b/cmd/kulalafmt/about.go
new file mode 100644
index 0000000..db7fae8
--- /dev/null
+++ b/cmd/kulalafmt/about.go
@@ -0,0 +1,19 @@
+package kulalafmt
+
+import (
+ "fmt"
+
+ "github.com/spf13/cobra"
+)
+
+var aboutCmd = &cobra.Command{
+ Use: "about",
+ Short: "Shows information about kulala-fmt",
+ Run: func(cmd *cobra.Command, args []string) {
+ fmt.Println("Made with ❤️ by Marco Kellershoff - https://gorilla.moe")
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(aboutCmd)
+}
\ No newline at end of file
diff --git a/cmd/kulalafmt/root.go b/cmd/kulalafmt/root.go
new file mode 100644
index 0000000..19d0624
--- /dev/null
+++ b/cmd/kulalafmt/root.go
@@ -0,0 +1,36 @@
+package kulalafmt
+
+import (
+ "os"
+
+ "github.com/charmbracelet/log"
+ "github.com/mistweaverco/kulala-fmt/internal/config"
+ "github.com/mistweaverco/kulala-fmt/internal/parser"
+ "github.com/spf13/cobra"
+)
+
+var cfg = config.NewConfig(config.Config{})
+
+var rootCmd = &cobra.Command{
+ Use: "kulala-fmt",
+ Short: "An opinionated 🦄 .http and .rest 🐼 files linter 💄 and formatter ⚡.",
+ Long: "Formats and lints .http and .rest files in the current directory and subdirectories.",
+ Run: func(cmd *cobra.Command, args []string) {
+ if len(args) == 0 {
+ log.Info("Starting kulala-fmt 🦄", "version", VERSION)
+ parser.Start(cfg.GetConfigFlags())
+ }
+ },
+}
+
+func Execute() {
+ err := rootCmd.Execute()
+ if err != nil {
+ os.Exit(1)
+ }
+}
+
+func init() {
+ rootCmd.PersistentFlags().BoolVar(&cfg.Flags.DryRun, "dry-run", false, "dry run")
+ rootCmd.PersistentFlags().BoolVar(&cfg.Flags.Check, "check", false, "check")
+}
\ No newline at end of file
diff --git a/cmd/kulalafmt/version.go b/cmd/kulalafmt/version.go
new file mode 100644
index 0000000..053d523
--- /dev/null
+++ b/cmd/kulalafmt/version.go
@@ -0,0 +1,22 @@
+package kulalafmt
+
+import (
+ "runtime"
+
+ "github.com/charmbracelet/log"
+ "github.com/spf13/cobra"
+)
+
+var VERSION string
+
+var versionCmd = &cobra.Command{
+ Use: "version",
+ Short: "Print the version number of kulala-fmt",
+ Run: func(cmd *cobra.Command, args []string) {
+ log.Info("Version", runtime.GOOS, VERSION)
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(versionCmd)
+}
\ No newline at end of file
diff --git a/dist/.gitignore b/dist/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/dist/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..b2a20e3
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,24 @@
+module github.com/mistweaverco/kulala-fmt
+
+go 1.22
+
+require (
+ github.com/charmbracelet/log v0.4.0
+ github.com/spf13/cobra v1.8.0
+)
+
+require (
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/charmbracelet/lipgloss v0.10.0 // indirect
+ github.com/go-logfmt/logfmt v0.6.0 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/muesli/reflow v0.3.0 // indirect
+ github.com/muesli/termenv v0.15.2 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
+ golang.org/x/sys v0.20.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..be8f88d
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,45 @@
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
+github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
+github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
+github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
+github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
+github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
+github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
+github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..0086e37
Binary files /dev/null and b/icon.png differ
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..3b1eae8
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1 @@
+
diff --git a/internal/config/config.go b/internal/config/config.go
new file mode 100644
index 0000000..8a8bea8
--- /dev/null
+++ b/internal/config/config.go
@@ -0,0 +1,18 @@
+package config
+
+type ConfigFlags struct {
+ DryRun bool
+ Check bool
+}
+
+type Config struct {
+ Flags ConfigFlags
+}
+
+func (c Config) GetConfigFlags() ConfigFlags {
+ return c.Flags
+}
+
+func NewConfig(cfg Config) Config {
+ return cfg
+}
\ No newline at end of file
diff --git a/internal/parser/parser.go b/internal/parser/parser.go
new file mode 100644
index 0000000..247193f
--- /dev/null
+++ b/internal/parser/parser.go
@@ -0,0 +1,21 @@
+package parser
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/mistweaverco/kulala-fmt/internal/config"
+)
+
+func Start(flags config.ConfigFlags) {
+ // get all files in the current directory and subdirectories that match the file extension .http or .rest
+ files := []string{}
+ _ = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+ if filepath.Ext(path) == ".http" || filepath.Ext(path) == ".rest" {
+ files = append(files, path)
+ }
+ return nil
+ })
+ fmt.Println(files)
+}
\ No newline at end of file
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..675eaf9
--- /dev/null
+++ b/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "github.com/mistweaverco/kulala-fmt/cmd/kulalafmt"
+
+func main() {
+ kulalafmt.Execute()
+}
\ No newline at end of file