penguin/AstroJS

Javascript framework for my blog

resolver-go/cmd/externs-gen/main.go

raw ยท 1616 bytes

package main

import (
	"flag"
	"fmt"
	"go/format"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	src := flag.String("src", "./src", "BotanJS source root")
	out := flag.String("out", "internal/generated/externs_gen.go", "generated Go output")
	pkg := flag.String("pkg", "generated", "generated package name")
	flag.Parse()

	if err := os.MkdirAll(filepath.Dir(*out), 0o755); err != nil {
		fatal(err)
	}

	code, err := render(*pkg, *src)
	if err != nil {
		fatal(err)
	}

	fmted, err := format.Source([]byte(code))
	if err != nil {
		_, _ = os.Stderr.WriteString(code)
		fatal(err)
	}

	if err := os.WriteFile(*out, fmted, 0o644); err != nil {
		fatal(err)
	}
}

func render(pkg string, root string) (string, error) {
	var b strings.Builder

	root = filepath.Clean(root)

	b.WriteString("// Code generated by externs-gen; DO NOT EDIT.\n")
	b.WriteString("package " + pkg + "\n\n")
	b.WriteString("var Externs = []string{\n")

	err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		if d.IsDir() {
			return nil
		}

		if filepath.Ext(path) != ".js" {
			return nil
		}

		if filepath.Base(filepath.Dir(path)) != "externs" {
			return nil
		}

		rel, err := filepath.Rel(root, path)
		if err != nil {
			return err
		}

		// Generated data should be slash-normalized even on Windows.
		rel = filepath.ToSlash(rel)

		fmt.Fprintf(&b, "\t%q,\n", rel)
		return nil
	})
	if err != nil {
		return "", err
	}

	b.WriteString("}\n")
	return b.String(), nil
}

func fatal(err error) {
	fmt.Fprintln(os.Stderr, "externs-gen:", err)
	os.Exit(1)
}