g4s8/envdoc

Panic on generate

Posya opened this issue · 4 comments

Hello!

I'm trying to make documentation out of a structure
There is a config.Config structure, and nested structures in different packages

package config
//go:generate go run github.com/g4s8/envdoc@latest -output environments.md
type Config struct {
	ProgName         string `env:"PROG_NAME,notEmpty" envDefault:"prog"`
	Logger           log.Config

	Application lifecycle.Config
	RestAPI     restapi.Config
}

package log
type Config struct {
	Level    string `env:"LOG_LEVEL,notEmpty"  envDefault:"info"`
	Format   string `env:"LOG_FORMAT,notEmpty" envDefault:"json"`
}

package lifecycle
type Config struct {
	AppGracePeriod        time.Duration `env:"APP_GRACE_PERIOD,notEmpty"        envDefault:"10s"`
}

package restapi
type Config struct {
	Port         int           `env:"RESTAPI_PORT"          envDefault:"8080"`
	ReadTimeout  time.Duration `env:"RESTAPI_READ_TIMEOUT"  envDefault:"5s"`
	WriteTimeout time.Duration `env:"RESTAPI_WRITE_TIMEOUT" envDefault:"10s"`
	IdleTimeout  time.Duration `env:"RESTAPI_IDLE_TIMEOUT"  envDefault:"120s"`
}

When trying to generate an error is thrown

go generate ./internal/config/...
panic: expected type node root child, got nodeField (Config)

goroutine 1 [running]:
main.(*inspector).traverseAST(0xc0000bdc60, 0xc0000bf200, {0xc000012ad0, 0x6})
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/inspector.go:64 +0x445
main.(*inspector).inspectFile(0xc0000bdc60, {0xc0000120c7, 0x9})
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/inspector.go:51 +0x308
main.(*generator).generate(0xc00007f110, {0x60b9e8, 0xc00005aa98})
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/generator.go:99 +0xc6
main.run(0xc0000bde40)
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/main.go:133 +0x629
main.main()
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/main.go:70 +0x12a
exit status 2
internal/config/config.go:20: running "go": exit status 1

I've just tried your example (just removed package declarations), and it generated this environments.md file:

# Environment Variables

## Config

 - `PROG_NAME` (**required**, non-empty, default: `prog`) - 

## Config

 - `LOG_LEVEL` (**required**, non-empty, default: `info`) - 
 - `LOG_FORMAT` (**required**, non-empty, default: `json`) - 

## Config

 - `APP_GRACE_PERIOD` (**required**, non-empty, default: `10s`) - 

## Config

 - `RESTAPI_PORT` (default: `8080`) - 
 - `RESTAPI_READ_TIMEOUT` (default: `5s`) - 
 - `RESTAPI_WRITE_TIMEOUT` (default: `10s`) - 
 - `RESTAPI_IDLE_TIMEOUT` (default: `120s`) - 

Original source file:

package config

import (
	"time"

	"github.com/g4s8/go-lifecycle/pkg/lifecycle"
	"github.com/ipfs/go-log/v2"
)

//go:generate go run github.com/g4s8/envdoc@latest -output environments.md
type Config struct {
	ProgName string `env:"PROG_NAME,notEmpty" envDefault:"prog"`
	Logger   log.Config

	Application lifecycle.Config
	RestAPI     restapi.Config
}

type Config struct {
	Level  string `env:"LOG_LEVEL,notEmpty"  envDefault:"info"`
	Format string `env:"LOG_FORMAT,notEmpty" envDefault:"json"`
}

type Config struct {
	AppGracePeriod time.Duration `env:"APP_GRACE_PERIOD,notEmpty"        envDefault:"10s"`
}

type Config struct {
	Port         int           `env:"RESTAPI_PORT"          envDefault:"8080"`
	ReadTimeout  time.Duration `env:"RESTAPI_READ_TIMEOUT"  envDefault:"5s"`
	WriteTimeout time.Duration `env:"RESTAPI_WRITE_TIMEOUT" envDefault:"10s"`
	IdleTimeout  time.Duration `env:"RESTAPI_IDLE_TIMEOUT"  envDefault:"120s"`
}

Maybe you have some old cached version of envdoc?

Could you try using the latest version manually:

//go:generate go run github.com/g4s8/envdoc@v0.2.1 -output environments.md

And please add the output of go version here.

Hello!

Could you try using the latest version manually

The same:

panic: expected type node root child, got nodeField (Config)

goroutine 1 [running]:
main.(*inspector).traverseAST(0xc00008fc60, 0xc000157200, {0xc0001209d0, 0x6})
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/inspector.go:64 +0x445
main.(*inspector).inspectFile(0xc00008fc60, {0xc000012107, 0x9})
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/inspector.go:51 +0x308
main.(*generator).generate(0xc00011d110, {0x60b9e8, 0xc00010ea90})
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/generator.go:99 +0xc6
main.run(0xc00008fe40)
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/main.go:133 +0x629
main.main()
        /root/go/pkg/mod/github.com/g4s8/envdoc@v0.2.1/main.go:70 +0x12a
exit status 2
internal/config/config.go:20: running "go": exit status 1

And please add the output of go version here

go version go1.22.0 linux/amd64

Ok, I got a different result:

File tree structure:

.
├── go.mod
├── go.sum
├── internal
│     ├── config
│     │     └── config.go
│     ├── lifecycle
│     │     └── l.go
│     ├── log
│     │     └── l.go
│     └── restapi
│         └── r.go
└── main.go

Files:

  • ./internal/config/config.go
package config

import (
        "tmp/internal/lifecycle"
        "tmp/internal/log"
        "tmp/internal/restapi"
)

//go:generate go run github.com/g4s8/envdoc@latest -output environments.md
type Config struct {
        ProgName string `env:"PROG_NAME,notEmpty" envDefault:"prog"`
        Logger   log.Config

        Application lifecycle.Config
        RestAPI     restapi.Config
}
  • ./internal/lifecycle/l.go
package lifecycle

import "time"

type Config struct {
        AppGracePeriod time.Duration `env:"APP_GRACE_PERIOD,notEmpty"        envDefault:"10s"`
}
  • ./internal/log/l.go
package log

type Config struct {
        Level  string `env:"LOG_LEVEL,notEmpty"  envDefault:"info"`
        Format string `env:"LOG_FORMAT,notEmpty" envDefault:"json"`
}
  • ./internal/restapi/r.go
package restapi

import "time"

type Config struct {
        Port         int           `env:"RESTAPI_PORT"          envDefault:"8080"`
        ReadTimeout  time.Duration `env:"RESTAPI_READ_TIMEOUT"  envDefault:"5s"`
        WriteTimeout time.Duration `env:"RESTAPI_WRITE_TIMEOUT" envDefault:"10s"`
        IdleTimeout  time.Duration `env:"RESTAPI_IDLE_TIMEOUT"  envDefault:"120s"`
}

MD file generation works, although the result is somewhat truncated

# Environment Variables

## Config

 - `PROG_NAME` (**required**, non-empty, default: `prog`) -

The problem here is that go generate tools with AST parsers are working with source files, not packages, so it's not possible to resolve the type from another package automatically. I see two solutions to fix that:

  • provide some kind of parameter for project root, and parse the whole project to process all types, e.g. -project-root ./../..
  • manually specify additional files to include: -include ./restapi/r.go

Need to think about better solution