Case Converter — Go source
Convert text between UPPER, lower, Title, Sentence, camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE and slug. Live, one-click copy.
This is the Go implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Package caseconverter is the Go twin of CosmoDev's src/lib/case.ts (dual
// source: the web lib is TypeScript, the CLI lib is Go — kept in lock-step).
// Pure + deterministic, never panics. The table-driven tests in
// case-converter_test.go share vectors with src/lib/case.test.ts so the two
// implementations are held to the same contract.
//
// Pipeline mirrors the TS lib exactly: split into words (insert a space at
// each lowercase/digit→uppercase boundary, split on any run of
// whitespace/underscore/hyphen/dot, strip remaining non-alphanumeric chars
// from each token, drop empties), then apply the requested casing.
package caseconverter
import (
"regexp"
"strings"
)
// camelBoundary inserts a space between a lowercase letter or digit and a
// following uppercase letter, mirroring /([a-z0-9])([A-Z])/g in the TS lib.
var camelBoundary = regexp.MustCompile(`([a-z0-9])([A-Z])`)
// delimRun is the word splitter: any run of whitespace, underscore, hyphen, or
// dot — mirroring /[\s_\-.]+/ in the TS lib.
var delimRun = regexp.MustCompile(`[\s_.\-]+`)
// nonAlnum matches a single non-alphanumeric char, mirroring /[^a-zA-Z0-9]/g.
var nonAlnum = regexp.MustCompile(`[^a-zA-Z0-9]`)
// wordRun matches a word char followed by any run of non-whitespace — the
// title transform's replacement target, mirroring /\w\S*/g in the TS lib.
var wordRun = regexp.MustCompile(`\w\S*`)
// Words splits text into clean alphanumeric words. It is the Go twin of
// words() in src/lib/case.ts: insert a space at each camelCase boundary, split
// on any run of whitespace/underscore/hyphen/dot, strip remaining
// non-alphanumeric chars from each token, then drop empties.
func Words(s string) []string {
s = camelBoundary.ReplaceAllString(s, "$1 $2")
parts := delimRun.Split(s, -1)
out := make([]string, 0, len(parts))
for _, w := range parts {
w = nonAlnum.ReplaceAllString(w, "")
if w != "" {
out = append(out, w)
}
}
return out
}
// Cap uppercases the first rune and lowercases the rest. It is the Go twin of
// cap() in src/lib/case.ts; the empty string is returned unchanged.
func Cap(s string) string {
if s == "" {
return ""
}
r := []rune(s)
return strings.ToUpper(string(r[0])) + strings.ToLower(string(r[1:]))
}
// Upper returns s with all letters uppercased. Twin of caseTransforms.upper.
func Upper(s string) string { return strings.ToUpper(s) }
// Lower returns s with all letters lowercased. Twin of caseTransforms.lower.
func Lower(s string) string { return strings.ToLower(s) }
// Title uppercases the first letter and lowercases the rest of each
// whitespace-delimited token, preserving the original spacing/punctuation.
// Twin of caseTransforms.title (s.replace(/\w\S*/g, cap)).
func Title(s string) string {
return wordRun.ReplaceAllStringFunc(s, Cap)
}
// Sentence lowercases and trims s, then uppercases its first letter. The
// empty string stays empty. Twin of caseTransforms.sentence.
func Sentence(s string) string {
t := strings.ToLower(strings.TrimSpace(s))
if t == "" {
return ""
}
r := []rune(t)
return strings.ToUpper(string(r[0])) + string(r[1:])
}
// Camel joins the words of s with the first lowercased and the rest capped.
// Twin of caseTransforms.camel.
func Camel(s string) string {
ws := Words(s)
for i, w := range ws {
if i == 0 {
ws[i] = strings.ToLower(w)
} else {
ws[i] = Cap(w)
}
}
return strings.Join(ws, "")
}
// Pascal joins the words of s, each capped. Twin of caseTransforms.pascal.
func Pascal(s string) string {
ws := Words(s)
for i, w := range ws {
ws[i] = Cap(w)
}
return strings.Join(ws, "")
}
// Snake joins the lowercased words of s with underscores. Twin of
// caseTransforms.snake.
func Snake(s string) string {
return strings.ToLower(strings.Join(Words(s), "_"))
}
// Kebab joins the lowercased words of s with hyphens. Twin of
// caseTransforms.kebab.
func Kebab(s string) string {
return strings.ToLower(strings.Join(Words(s), "-"))
}
// Constant joins the uppercased words of s with underscores. Twin of
// caseTransforms.constant.
func Constant(s string) string {
return strings.ToUpper(strings.Join(Words(s), "_"))
}
// Slug joins the lowercased words of s with hyphens. Twin of
// caseTransforms.slug.
func Slug(s string) string {
return strings.ToLower(strings.Join(Words(s), "-"))
}
// CaseId names a case transform, mirroring the CaseId union in
// src/lib/case.ts. The string value matches the TS object key.
type CaseId string
const (
CaseUpper CaseId = "upper"
CaseLower CaseId = "lower"
CaseTitle CaseId = "title"
CaseSentence CaseId = "sentence"
CaseCamel CaseId = "camel"
CasePascal CaseId = "pascal"
CaseSnake CaseId = "snake"
CaseKebab CaseId = "kebab"
CaseConstant CaseId = "constant"
CaseSlug CaseId = "slug"
)
// Transform applies the named case transform to s. It mirrors
// caseTransforms[id] in the TS lib. An unknown id returns ("", false) — never
// a panic, mirroring the TS keyed lookup returning undefined.
func Transform(id CaseId, s string) (string, bool) {
switch id {
case CaseUpper:
return Upper(s), true
case CaseLower:
return Lower(s), true
case CaseTitle:
return Title(s), true
case CaseSentence:
return Sentence(s), true
case CaseCamel:
return Camel(s), true
case CasePascal:
return Pascal(s), true
case CaseSnake:
return Snake(s), true
case CaseKebab:
return Kebab(s), true
case CaseConstant:
return Constant(s), true
case CaseSlug:
return Slug(s), true
}
return "", false
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →