Korin is an experimental Golang preprocessor designed for learning and fun. It empowers developers to minimize code duplication by enabling preprocessing before compilation. By embedding directly into your codebase, Korin enhances code maintainability with its extensible plugin architecture.
Korin processes your Golang code line-by-line, allowing plugins to analyze, modify, or extend the code dynamically. Each plugin can:
- Add new lines
- Modify existing lines
- Transform specific code patterns
The k:float
plugin automates error propagation:
stats, _ := json.Marshal(statistics) // +k:float
Becomes:
stats, err := json.Marshal(statistics)
if err != nil {
return
}
This transformation ensures proper error handling, returning the zero value based on the function's result type (e.g., 0
for int
, ""
for string
). The source code for this plugin can be found in plugin_error_propagation.go
.
The k:named
plugin generates field annotations based on field names. For instance:
type Test struct {
NameCharacters string // +k:named(json,yaml,bson)
}
// +k:named(json,yaml,bson)
type TestWithMultiline struct {
NameCharacters string
Age int
}
Transforms to:
type Test struct {
NameCharacters string `json:"name_characters" yaml:"name_characters" bson:"name_characters"`
}
type TestWithMultiline struct {
NameCharacters string `json:"name_characters" yaml:"name_characters" bson:"name_characters"`
Age int `json:"age" yaml:"age" bson:"age"`
}
You can customize the case format:
- Camel Case:
type Test struct { NameCharacters string // +k:named(camelCase,json,yaml,bson) }
- Snake Case: Default behavior.
- Original Name:
type Test struct { NameCharacters string // +k:named(original,json,yaml,bson) }
The k:env
plugin automatically sets the value of a variable to its corresponding environment value. For instance:
var Port = "{$ENV:PORT}" // +k:env
Transforms to:
var Port = "8080"
You can also specify a type, and Korin will try to automatically convert it to that value on the fly. For instance:
const Port = "{$ENV:PORT}" // +k:env(int)
When using the types bool
, any int
, any float
, or rune
, Korin will automatically drop the value of the environment variable
as is, for instance, with the above code, it becomes:
const Port int = 8080
Otherwise, if it's a string
or an unknown type, such as a typealias, or a custom type, Korin will automatically convert the value to a string, for instance:
const Port = "{$ENV:PORT}" // +k:env(PortType)
Transforms to:
const Port PortType = "8080"
Korin supports preprocessing for:
- Type declarations
- Field declarations
- Variable declarations
- Function declarations (including anonymous functions)
- Import declarations
- Package declarations
- Return statements
- Comment declarations
- Const declarations (including multiple constants)
- Var declarations (including multiple variables)
Korin intercepts the entry point to preprocess your codebase. To use Korin, create a cmd/korin.go
file and add the following:
package main
import "github.com/ShindouMihou/korin/pkg/korin"
func main() {
k := korin.New()
// Uncomment to silence the logger (error logs during preprocessing remain unaffected)
// k.Logger = kbuild.NoOpLogger
// Specify the module name, this will skip reading the `go.mod` to find the module name, which can
// make preprocessing somewhat faster (not significantly since we only read one line).
// k.ModuleName = "github.com/ShindouMihou/korin"
// Specifying the location of your go.mod, not providing a ModuleName, and also not providing the correct
// path to your go.mod will result in an error since it cannot find the Module Name.
// k.ModulePath = "./go.mod"
// Replace with your actual entry point
k.Run("cmd/app.go")
}
Korin scans the codebase (excluding files listed in .korignore
), preprocesses required files, and outputs them to the configured build directory (default: .build
).
We recommend using Korin as a build step in Dockerfile to ensure that the code is preprocessed before building. To use Korin as a Docker build step, we recommend creating a
file called cmd/korin_build.go
and adding the following:
package main
import "github.com/ShindouMihou/korin/pkg/korin"
func main() {
korin := korin.New()
// Uncomment to silence the logger (error logs during preprocessing remain unaffected)
// korin.Logger = kbuild.NoOpLogger
korin.DockerBuildStep(".") // Replace with your path to source files if it isn't "."
}
Once done, you can add RUN go run cmd/korin_build.go
as a Docker step and it should preprocess the files beforehand. It is recommended to use this method over Build
and
related since it will exit the program with an exit code when it fails to preprocess a specific file.
To create a plugin, you can read about it in the Creating a Plugin documentation, otherwise,
you can check out the native plugins that are already available, these should have the plugin_
prefix on their filenames, by
default, all these plugins are automatically included when you create a new korin
instance.
Korin processes a 2,000-4,000 line codebase in under 5-10 milliseconds on average, though performance may vary depending on project complexity.
Korin is licensed under the MIT License. You are free to use, modify, and distribute this project in compliance with the license terms.
Elevate your Golang projects with Korin's seamless preprocessing capabilities!