mirror of
https://github.com/chenasraf/gi_gen.git
synced 2026-05-17 17:48:01 +00:00
refactor: file structure
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
||||
|
||||
28
.vscode/launch.json
vendored
28
.vscode/launch.json
vendored
@@ -1,15 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "gi_gen.go"
|
||||
}
|
||||
]
|
||||
}
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "main.go"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
33
cmd/gi_gen.go
Normal file
33
cmd/gi_gen.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/chenasraf/gi_gen/internal"
|
||||
)
|
||||
|
||||
func RunMainCmd() {
|
||||
wd, err := os.Getwd()
|
||||
HandleErr(err)
|
||||
|
||||
outFile := filepath.Join(wd, ".gitignore")
|
||||
allFiles, err := PrepareGitignores()
|
||||
HandleErr(err)
|
||||
|
||||
fileNames, files := GetRelevantFiles(allFiles)
|
||||
|
||||
log.Println("Done.")
|
||||
|
||||
selected, selectedKeys := GetLanguageSelections(files, fileNames)
|
||||
cleanupSelection := GetCleanupSelection()
|
||||
outContents := Ternary(cleanupSelection, CleanupMultiple(selected, selectedKeys), GetAllRaw(selected, selectedKeys))
|
||||
|
||||
if FileExists(outFile) {
|
||||
HandleFileOverwrite(outFile, outContents)
|
||||
} else {
|
||||
log.Printf("Writing to %s", outFile)
|
||||
WriteFile(outFile, outContents, true)
|
||||
}
|
||||
}
|
||||
54
gi_gen.go
54
gi_gen.go
@@ -1,54 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
wd, err := os.Getwd()
|
||||
handleErr(err)
|
||||
|
||||
outFile := filepath.Join(wd, ".gitignore")
|
||||
allFiles, err := prepareGitignores()
|
||||
|
||||
handleErr(err)
|
||||
|
||||
fileNames, files := getPossibleFiles(allFiles)
|
||||
|
||||
log.Println("Done.")
|
||||
|
||||
selected, selectedKeys := getLanguages(files, fileNames)
|
||||
|
||||
cleanupSelection := getCleanupSelection()
|
||||
var outContents string
|
||||
if cleanupSelection {
|
||||
out := []string{}
|
||||
for i, selection := range selected {
|
||||
cleanSelection := removeUnusedPatterns(selection)
|
||||
if strings.TrimSpace(cleanSelection) == "" {
|
||||
continue
|
||||
}
|
||||
header := langHeader(selectedKeys[i])
|
||||
prefixNewline := ternary(i > 0, "\n", "")
|
||||
contents := prefixNewline + header + cleanSelection
|
||||
out = append(out, contents)
|
||||
}
|
||||
outContents = strings.Join(out, "\n")
|
||||
} else {
|
||||
for i, selection := range selected {
|
||||
header := langHeader(selectedKeys[i])
|
||||
selected[i] = header + selection
|
||||
}
|
||||
outContents = strings.Join(selected, "\n")
|
||||
}
|
||||
|
||||
if fileExists(outFile) {
|
||||
handleFileOverwrite(outFile, outContents)
|
||||
} else {
|
||||
log.Printf("Writing to %s", outFile)
|
||||
writeFile(outFile, outContents, true)
|
||||
}
|
||||
}
|
||||
151
ignore_files.go
151
ignore_files.go
@@ -1,151 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func prepareGitignores() ([]string, error) {
|
||||
gitignoresDir := getCacheDir()
|
||||
|
||||
if !fileExists(gitignoresDir) {
|
||||
log.Println("Getting gitignore files...")
|
||||
runCmd("git", "clone", "--depth=1", repoUrl, gitignoresDir)
|
||||
}
|
||||
|
||||
if getNeedsUpdate() {
|
||||
log.Println("Updating gitignore files...")
|
||||
runCmd("git", "pull", "origin", "master")
|
||||
os.RemoveAll(filepath.Join(gitignoresDir, ".git"))
|
||||
}
|
||||
|
||||
return getGitignores(gitignoresDir)
|
||||
}
|
||||
|
||||
func getCacheDir() string {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
gitignoresDir := filepath.Join(homeDir, ".github.gitignore")
|
||||
return gitignoresDir
|
||||
}
|
||||
|
||||
func getGitignores(sourceDir string) ([]string, error) {
|
||||
return filepath.Glob(filepath.Join(sourceDir, "*.gitignore"))
|
||||
}
|
||||
|
||||
var ignoreLines = []string{
|
||||
"/*",
|
||||
".",
|
||||
".vscode",
|
||||
".vscode/*",
|
||||
".idea",
|
||||
".idea/*",
|
||||
}
|
||||
|
||||
func findFileMatches(patterns string) bool {
|
||||
lines := strings.Split(patterns, "\n")
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
// ignore empty lines / comments
|
||||
if len(line) == 0 || strings.ToLower(line)[0] == '#' {
|
||||
continue
|
||||
}
|
||||
idx := strings.Index(line, "#")
|
||||
// ignore comments at end of line
|
||||
if idx > -1 && (idx == 0 || line[idx-1] != '\\') {
|
||||
line = strings.TrimSpace(line[0:idx])
|
||||
}
|
||||
if len(line) == 0 || contains(ignoreLines, line) {
|
||||
continue
|
||||
}
|
||||
if globExists(filepath.Join(wd, line)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var patternCache []string = []string{}
|
||||
|
||||
func removeUnusedPatterns(contents string) string {
|
||||
wd, _ := os.Getwd()
|
||||
lines := strings.Split(contents, "\n")
|
||||
keep := []string{}
|
||||
lastTakenIdx := -1
|
||||
|
||||
for i, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
|
||||
if len(trimmed) == 0 || trimmed[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
if globExists(filepath.Join(wd, trimmed)) {
|
||||
if contains(patternCache, trimmed) {
|
||||
continue
|
||||
}
|
||||
|
||||
patternCache = append(patternCache, trimmed)
|
||||
|
||||
if i > 0 {
|
||||
j := 1
|
||||
foundComment := false
|
||||
comments := []string{}
|
||||
for {
|
||||
if i-j < 0 || i-j <= lastTakenIdx {
|
||||
break
|
||||
}
|
||||
cur := lines[i-j]
|
||||
if len(cur) > 0 && cur[0] != '#' {
|
||||
if !foundComment {
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
lastTakenIdx = i - j
|
||||
if len(cur) > 0 && cur[0] == '#' {
|
||||
foundComment = true
|
||||
}
|
||||
comments = insert(comments, 0, cur)
|
||||
}
|
||||
j++
|
||||
}
|
||||
for _, v := range comments {
|
||||
keep = append(keep, v)
|
||||
}
|
||||
}
|
||||
|
||||
keep = append(keep, line)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(keep, "\n")
|
||||
}
|
||||
|
||||
func getLanguages(files map[string]string, fileNames []string) ([]string, []string) {
|
||||
selected := []string{}
|
||||
allKeys := maps.Keys(files)
|
||||
selectedKeys := maps.Keys(files)
|
||||
|
||||
if len(allKeys) > 1 {
|
||||
selected, selectedKeys = getLanguageSelections(fileNames, selected, files)
|
||||
} else {
|
||||
selected = []string{files[allKeys[0]]}
|
||||
}
|
||||
|
||||
return selected, selectedKeys
|
||||
}
|
||||
|
||||
func langHeader(langName string) string {
|
||||
sep := "#========================================================================\n"
|
||||
header := fmt.Sprintf(sep+"# %s\n"+sep+"\n", langName)
|
||||
return header
|
||||
}
|
||||
@@ -1,33 +1,31 @@
|
||||
package main
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
)
|
||||
|
||||
func handleFileOverwrite(path string, contents string) {
|
||||
overwriteSelection := getOverwriteSelection()
|
||||
func HandleFileOverwrite(path string, contents string) {
|
||||
overwriteSelection := AskOverwrite()
|
||||
switch overwriteSelection {
|
||||
case "":
|
||||
quit()
|
||||
Quit()
|
||||
break
|
||||
case "Overwrite":
|
||||
log.Printf("Writing to %s", path)
|
||||
writeFile(path, contents, true)
|
||||
WriteFile(path, contents, true)
|
||||
break
|
||||
case "Append":
|
||||
log.Printf("Appending to %s", path)
|
||||
writeFile(path, contents, false)
|
||||
WriteFile(path, contents, false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func getOverwriteSelection() string {
|
||||
func AskOverwrite() string {
|
||||
overwritePrompt := &survey.Select{
|
||||
Message: ".gitignore file found in this directory. Please pick an option:",
|
||||
Options: []string{"Overwrite", "Append", "Skip"},
|
||||
@@ -37,7 +35,7 @@ func getOverwriteSelection() string {
|
||||
return overwriteSelection
|
||||
}
|
||||
|
||||
func getCleanupSelection() bool {
|
||||
func GetCleanupSelection() bool {
|
||||
cleanupPrompt := &survey.Confirm{
|
||||
Message: "Do you want to remove patterns not existing in your project?",
|
||||
Default: true,
|
||||
@@ -48,7 +46,7 @@ func getCleanupSelection() bool {
|
||||
return cleanupSelection
|
||||
}
|
||||
|
||||
func getLanguageSelections(fileNames []string, selected []string, files map[string]string) ([]string, []string) {
|
||||
func AskLanguage(fileNames []string, selected []string, files map[string]string) ([]string, []string) {
|
||||
langPrompt := &survey.MultiSelect{
|
||||
Message: "Found " + fmt.Sprint(len(fileNames)) +
|
||||
" possible matches in your project for gitignore files.\n" +
|
||||
@@ -59,7 +57,7 @@ func getLanguageSelections(fileNames []string, selected []string, files map[stri
|
||||
var langSelections []string
|
||||
survey.AskOne(langPrompt, &langSelections)
|
||||
if langSelections == nil {
|
||||
quit()
|
||||
Quit()
|
||||
}
|
||||
keys := []string{}
|
||||
for _, selection := range langSelections {
|
||||
@@ -70,10 +68,7 @@ func getLanguageSelections(fileNames []string, selected []string, files map[stri
|
||||
return selected, keys
|
||||
}
|
||||
|
||||
func getPossibleFiles(allFiles []string) ([]string, map[string]string) {
|
||||
files := make(map[string]string)
|
||||
fileNames := []string{}
|
||||
|
||||
func AskDiscovery() bool {
|
||||
prompt := &survey.Confirm{
|
||||
Message: "Would you like to try to scan for available templates automatically?\n" +
|
||||
"Select 'No' ('n') to see all available templates",
|
||||
@@ -81,26 +76,9 @@ func getPossibleFiles(allFiles []string) ([]string, map[string]string) {
|
||||
}
|
||||
var answer bool
|
||||
survey.AskOne(prompt, &answer)
|
||||
|
||||
for _, filename := range allFiles {
|
||||
contents := readFile(filename)
|
||||
basename := filepath.Base(filename)
|
||||
langName := basename[:strings.Index(basename, ".")]
|
||||
|
||||
if answer {
|
||||
if findFileMatches(contents) {
|
||||
files[langName] = contents
|
||||
fileNames = append(fileNames, langName)
|
||||
}
|
||||
} else {
|
||||
files[langName] = contents
|
||||
fileNames = append(fileNames, langName)
|
||||
}
|
||||
}
|
||||
|
||||
return fileNames, files
|
||||
return answer
|
||||
}
|
||||
|
||||
func quit() {
|
||||
func Quit() {
|
||||
os.Exit(1)
|
||||
}
|
||||
204
internal/ignore_files.go
Normal file
204
internal/ignore_files.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func PrepareGitignores() ([]string, error) {
|
||||
gitignoresDir := GetCacheDir()
|
||||
|
||||
if !FileExists(gitignoresDir) {
|
||||
log.Println("Getting gitignore files...")
|
||||
RunCmd("git", "clone", "--depth=1", repoUrl, gitignoresDir)
|
||||
}
|
||||
|
||||
if GetNeedsUpdate() {
|
||||
log.Println("Updating gitignore files...")
|
||||
RunCmd("git", "pull", "origin", "master")
|
||||
os.RemoveAll(filepath.Join(gitignoresDir, ".git"))
|
||||
}
|
||||
|
||||
return GetGitignores(gitignoresDir)
|
||||
}
|
||||
|
||||
func GetCacheDir() string {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
gitignoresDir := filepath.Join(homeDir, ".github.gitignore")
|
||||
return gitignoresDir
|
||||
}
|
||||
|
||||
func GetGitignores(sourceDir string) ([]string, error) {
|
||||
return filepath.Glob(filepath.Join(sourceDir, "*.gitignore"))
|
||||
}
|
||||
|
||||
var ignoreLines = []string{
|
||||
"/*",
|
||||
".",
|
||||
".vscode",
|
||||
".vscode/*",
|
||||
".idea",
|
||||
".idea/*",
|
||||
}
|
||||
|
||||
func FindFileMatches(patterns string) bool {
|
||||
lines := strings.Split(patterns, "\n")
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
// ignore empty lines / comments
|
||||
if len(line) == 0 || strings.ToLower(line)[0] == '#' {
|
||||
continue
|
||||
}
|
||||
idx := strings.Index(line, "#")
|
||||
// ignore comments at end of line
|
||||
if idx > -1 && (idx == 0 || line[idx-1] != '\\') {
|
||||
line = strings.TrimSpace(line[0:idx])
|
||||
}
|
||||
if len(line) == 0 || Contains(ignoreLines, line) {
|
||||
continue
|
||||
}
|
||||
if GlobExists(filepath.Join(wd, line)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var patternCache []string = []string{}
|
||||
|
||||
func RemoveUnusedPatterns(contents string) string {
|
||||
wd, _ := os.Getwd()
|
||||
lines := strings.Split(contents, "\n")
|
||||
keep := []string{}
|
||||
lastTakenIdx := -1
|
||||
|
||||
for i, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
|
||||
if len(trimmed) == 0 || trimmed[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
if GlobExists(filepath.Join(wd, trimmed)) {
|
||||
if Contains(patternCache, trimmed) {
|
||||
continue
|
||||
}
|
||||
|
||||
patternCache = append(patternCache, trimmed)
|
||||
|
||||
if i > 0 {
|
||||
keep = GatherPreviousCommentGroup(i, lastTakenIdx, lines, keep)
|
||||
}
|
||||
|
||||
keep = append(keep, line)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(keep, "\n")
|
||||
}
|
||||
|
||||
func GatherPreviousCommentGroup(i int, lastTakenIdx int, lines []string, keep []string) []string {
|
||||
j := 1
|
||||
foundComment := false
|
||||
comments := []string{}
|
||||
for {
|
||||
if i-j < 0 || i-j <= lastTakenIdx {
|
||||
break
|
||||
}
|
||||
cur := lines[i-j]
|
||||
if len(cur) > 0 && cur[0] != '#' {
|
||||
if !foundComment {
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
lastTakenIdx = i - j
|
||||
if len(cur) > 0 && cur[0] == '#' {
|
||||
foundComment = true
|
||||
}
|
||||
comments = Insert(comments, 0, cur)
|
||||
}
|
||||
j++
|
||||
}
|
||||
for _, v := range comments {
|
||||
keep = append(keep, v)
|
||||
}
|
||||
return keep
|
||||
}
|
||||
|
||||
func GetLanguageSelections(files map[string]string, fileNames []string) ([]string, []string) {
|
||||
selected := []string{}
|
||||
allKeys := maps.Keys(files)
|
||||
selectedKeys := maps.Keys(files)
|
||||
|
||||
if len(allKeys) > 1 {
|
||||
selected, selectedKeys = AskLanguage(fileNames, selected, files)
|
||||
} else {
|
||||
selected = []string{files[allKeys[0]]}
|
||||
}
|
||||
|
||||
return selected, selectedKeys
|
||||
}
|
||||
|
||||
func GetRelevantFiles(allFiles []string) ([]string, map[string]string) {
|
||||
files := make(map[string]string)
|
||||
fileNames := []string{}
|
||||
|
||||
answer := AskDiscovery()
|
||||
|
||||
for _, filename := range allFiles {
|
||||
contents := ReadFile(filename)
|
||||
basename := filepath.Base(filename)
|
||||
langName := basename[:strings.Index(basename, ".")]
|
||||
|
||||
if answer {
|
||||
if FindFileMatches(contents) {
|
||||
files[langName] = contents
|
||||
fileNames = append(fileNames, langName)
|
||||
}
|
||||
} else {
|
||||
files[langName] = contents
|
||||
fileNames = append(fileNames, langName)
|
||||
}
|
||||
}
|
||||
|
||||
return fileNames, files
|
||||
}
|
||||
|
||||
func LangHeader(langName string) string {
|
||||
sep := "#========================================================================\n"
|
||||
header := fmt.Sprintf(sep+"# %s\n"+sep+"\n", langName)
|
||||
return header
|
||||
}
|
||||
|
||||
func GetAllRaw(selected []string, selectedKeys []string) string {
|
||||
for i, selection := range selected {
|
||||
header := LangHeader(selectedKeys[i])
|
||||
selected[i] = header + selection
|
||||
}
|
||||
return strings.Join(selected, "\n")
|
||||
}
|
||||
|
||||
func CleanupMultiple(selected []string, keys []string) string {
|
||||
out := []string{}
|
||||
for i, selection := range selected {
|
||||
cleanSelection := RemoveUnusedPatterns(selection)
|
||||
if strings.TrimSpace(cleanSelection) == "" {
|
||||
continue
|
||||
}
|
||||
header := LangHeader(keys[i])
|
||||
prefixNewline := Ternary(i > 0, "\n", "")
|
||||
contents := prefixNewline + header + cleanSelection
|
||||
out = append(out, contents)
|
||||
}
|
||||
return strings.Join(out, "\n")
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -14,19 +14,19 @@ func UNUSED(x ...interface{}) {}
|
||||
|
||||
var repoUrl = "https://github.com/github/gitignore"
|
||||
|
||||
func fileExists(path string) bool {
|
||||
func FileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
exists := !os.IsNotExist(err)
|
||||
return exists
|
||||
}
|
||||
|
||||
func globExists(path string) bool {
|
||||
func GlobExists(path string) bool {
|
||||
res, err := filepath.Glob(path)
|
||||
handleErr(err)
|
||||
HandleErr(err)
|
||||
return res != nil
|
||||
}
|
||||
|
||||
func getNeedsUpdate() bool {
|
||||
func GetNeedsUpdate() bool {
|
||||
localBytes, localErr := exec.Command("git", "rev-parse", "@").Output()
|
||||
baseBytes, baseErr := exec.Command("git", "merge-base", "@", "@{u}").Output()
|
||||
if localErr != nil {
|
||||
@@ -43,46 +43,46 @@ func getNeedsUpdate() bool {
|
||||
return localStr == baseStr
|
||||
}
|
||||
|
||||
func runCmd(cmd string, args ...string) (string, error) {
|
||||
func RunCmd(cmd string, args ...string) (string, error) {
|
||||
res, err := exec.Command(cmd, args...).Output()
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
func readFile(path string) string {
|
||||
func ReadFile(path string) string {
|
||||
res, err := os.ReadFile(path)
|
||||
handleErr(err)
|
||||
HandleErr(err)
|
||||
return string(res)
|
||||
}
|
||||
|
||||
func writeFile(path string, data string, overwrite bool) bool {
|
||||
func WriteFile(path string, data string, overwrite bool) bool {
|
||||
var err error
|
||||
if overwrite {
|
||||
// os.Create(path)
|
||||
err = os.WriteFile(path, []byte(data), fs.ModeAppend)
|
||||
handleErr(err)
|
||||
HandleErr(err)
|
||||
|
||||
} else {
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
handleErr(err)
|
||||
HandleErr(err)
|
||||
defer f.Close()
|
||||
_, err = f.WriteString("\n" + data)
|
||||
handleErr(err)
|
||||
HandleErr(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func handleErr(err error) {
|
||||
func HandleErr(err error) {
|
||||
if err != nil {
|
||||
log.Println("Encountered an error while running gi_gen:")
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func insert[T any](a []T, i int, item T) []T {
|
||||
func Insert[T any](a []T, i int, item T) []T {
|
||||
return append(a[:i], append([]T{item}, a[i:]...)...)
|
||||
}
|
||||
|
||||
func contains[T comparable](list []T, item T) bool {
|
||||
func Contains[T comparable](list []T, item T) bool {
|
||||
for _, v := range list {
|
||||
if v == item {
|
||||
return true
|
||||
@@ -91,13 +91,13 @@ func contains[T comparable](list []T, item T) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func ternary[T any](cond bool, whenTrue T, whenFalse T) T {
|
||||
func Ternary[T any](cond bool, whenTrue T, whenFalse T) T {
|
||||
if cond {
|
||||
return whenTrue
|
||||
}
|
||||
return whenFalse
|
||||
}
|
||||
|
||||
func toS[T any](obj T) string {
|
||||
func ToString[T any](obj T) string {
|
||||
return fmt.Sprint(obj)
|
||||
}
|
||||
Reference in New Issue
Block a user