feat: declare API errors and authentication with developer tooling

This commit is contained in:
2026-09-23 18:17:43 +08:00
parent ab8eac5fc4
commit 2913e94a0a
35 changed files with 2246 additions and 107 deletions

View File

@@ -25,12 +25,23 @@ type Options struct {
Database, Storage string
API, Dir, Module, FrameworkDir, FrameworkVersion, LogOutput, LogFormat string
Check bool
DryRun bool
}
type FileChange struct {
Path string
Action string
}
type Output struct {
Generated, Created, Preserved, Removed []string
Changes []FileChange
}
type Output struct{ Generated, Created, Preserved, Removed []string }
// Generate creates or safely updates one contract-driven project. It renders
// and validates every output before applying an ownership-checked transaction.
func Generate(o Options) (Output, error) {
if o.Check && o.DryRun {
return Output{}, errors.New("--check and --dry-run cannot be combined")
}
if o.API == "" || o.Dir == "" {
return Output{}, errors.New("--api and --dir are required")
}
@@ -49,8 +60,8 @@ const starterAPI = "syntax = \"v1\"\n\ninfo (\n title: \"Greeting API\"\n versio
// New creates a runnable greeting project, including its editable API file.
func New(o Options) (Output, error) {
if o.API != "" || o.Check {
return Output{}, errors.New("api new does not accept --api or --check")
if o.API != "" || o.Check || o.DryRun {
return Output{}, errors.New("api new does not accept --api, --check or --dry-run")
}
if o.Dir == "" {
return Output{}, errors.New("project directory required")
@@ -204,7 +215,7 @@ func generate(o Options, c *Compiled, starter bool) (Output, error) {
}
}
}
return apply(directory, o.Module, entry, generated, seeds, o.Check, o.profile())
return apply(directory, o.Module, entry, generated, seeds, o.Check, o.DryRun, o.profile())
}
func moduleFile(o Options) ([]byte, error) {
@@ -289,6 +300,13 @@ func canonical(path string) string {
func renderProject(o Options, c *Compiled, starter bool) (map[string][]byte, map[string][]byte, error) {
generated, seeds := map[string][]byte{}, map[string][]byte{}
put := func(files map[string][]byte, name, content string) { files[name] = []byte(content) }
if len(c.Spec.Errors) > 0 {
content := "package apierrors\nimport omnierrors " + strconv.Quote(frameworkModule+"/errors") + "\n"
for _, e := range c.Spec.Errors {
content += fmt.Sprintf("const Code%s = %q\n// %s returns a fresh public error declared in the API contract.\nfunc %s()*omnierrors.APIError{return omnierrors.New(%d,Code%s,%q)}\n", e.Name, e.Code, e.Name, e.Name, e.Status, e.Name, e.Message)
}
put(generated, "internal/apierrors/errorsGen.go", generatedHeader+content)
}
types := "package types\n\n"
for _, t := range c.Spec.Types {
types += "type " + t.Name + " struct {\n"