fork of indigo with slightly nicer lexgen

lexgen: add --external-lexicons (#1078)

`cmd/lexgen` is unprepared for a world where it's not generating schemas
for everything in `atproto`! Both type generation and server stub
generation generate types/stubs for every specified lexicon; this causes
generated code to be somewhere between "challenging" and "unusable" for
external projects — we'd prefer to have codegen that creates types for
our Go program while still being able to externally reference
`com.atproto` and `app.bsky` schema

This change introduces an `--external-lexicons` flag that can take
multiple directories. It functions the same way as the positional
lexicon arguments, those lexicons are all loaded into the code and can
be referenced, but their types/stubs are not included as part of the
generated output. This yields the following command for Streamplace;
this generates types for Streamplace lexicons without generating atproto
code:

```shell
lexgen \
-outdir ./pkg/spxrpc \
--build-file util/lexgen-types.json \
--external-lexicons ../atproto/lexicons \
lexicons/place/stream \
lexicons/app/bsky

```

And this does the same thing for generating server stubs:
```
lexgen \
--gen-server \
--types-import place.stream:stream.place/streamplace/pkg/streamplace \
--types-import app.bsky:github.com/bluesky-social/indigo/api/bsky \
--types-import com.atproto:github.com/bluesky-social/indigo/api/atproto \
--types-import chat.bsky:github.com/bluesky-social/indigo/api/chat \
--types-import tools.ozone:github.com/bluesky-social/indigo/api/ozone \
-outdir ./pkg/spxrpc \
--build-file util/lexgen-types.json \
--external-lexicons ../atproto/lexicons \
--package spxrpc \
lexicons/place/stream \
lexicons/app/bsky
```

`lexgen-types.json` looks like this:
```json
[
{
"package": "bsky",
"prefix": "app.bsky",
"outdir": "api/bsky",
"import": "github.com/bluesky-social/indigo/api/bsky"
},
{
"package": "atproto",
"prefix": "com.atproto",
"outdir": "api/atproto",
"import": "github.com/bluesky-social/indigo/api/atproto"
},
{
"package": "chat",
"prefix": "chat.bsky",
"outdir": "api/chat",
"import": "github.com/bluesky-social/indigo/api/chat"
},
{
"package": "ozone",
"prefix": "tools.ozone",
"outdir": "api/ozone",
"import": "github.com/bluesky-social/indigo/api/ozone"
},
{
"package": "streamplace",
"prefix": "place.stream",
"outdir": "./pkg/streamplace",
"import": "stream.place/streamplace"
}
]
```

This is a great tool, makes writing Go XRPC handlers really easy, let's
get it usable by the community!

EDIT: Oh also I removed `--prefix` which was referenced by nobody and
did nothing.

authored by Whyrusleeping and committed by GitHub 3edc6e26 7075cf22

Changed files
+21 -7
cmd
lexgen
lex
+19 -5
cmd/lexgen/main.go
··· 64 &cli.StringFlag{ 65 Name: "outdir", 66 }, 67 - &cli.StringFlag{ 68 - Name: "prefix", 69 - }, 70 &cli.BoolFlag{ 71 Name: "gen-server", 72 }, ··· 75 }, 76 &cli.StringSliceFlag{ 77 Name: "types-import", 78 }, 79 &cli.StringFlag{ 80 Name: "package", ··· 109 schemas = append(schemas, s) 110 } 111 112 buildLiteral := cctx.String("build") 113 buildPath := cctx.String("build-file") 114 var packages []lex.Package ··· 145 if outdir == "" { 146 return fmt.Errorf("must specify output directory (--outdir)") 147 } 148 - defmap := lex.BuildExtDefMap(schemas, packages) 149 _ = defmap 150 151 paths := cctx.StringSlice("types-import") ··· 162 } 163 164 } else { 165 - return lex.Run(schemas, packages) 166 } 167 168 return nil
··· 64 &cli.StringFlag{ 65 Name: "outdir", 66 }, 67 &cli.BoolFlag{ 68 Name: "gen-server", 69 }, ··· 72 }, 73 &cli.StringSliceFlag{ 74 Name: "types-import", 75 + }, 76 + &cli.StringSliceFlag{ 77 + Name: "external-lexicons", 78 }, 79 &cli.StringFlag{ 80 Name: "package", ··· 109 schemas = append(schemas, s) 110 } 111 112 + externalPaths, err := expandArgs(cctx.StringSlice("external-lexicons")) 113 + if err != nil { 114 + return err 115 + } 116 + var externalSchemas []*lex.Schema 117 + for _, arg := range externalPaths { 118 + s, err := lex.ReadSchema(arg) 119 + if err != nil { 120 + return fmt.Errorf("failed to read file %q: %w", arg, err) 121 + } 122 + 123 + externalSchemas = append(externalSchemas, s) 124 + } 125 + 126 buildLiteral := cctx.String("build") 127 buildPath := cctx.String("build-file") 128 var packages []lex.Package ··· 159 if outdir == "" { 160 return fmt.Errorf("must specify output directory (--outdir)") 161 } 162 + defmap := lex.BuildExtDefMap(append(schemas, externalSchemas...), packages) 163 _ = defmap 164 165 paths := cctx.StringSlice("types-import") ··· 176 } 177 178 } else { 179 + return lex.Run(schemas, externalSchemas, packages) 180 } 181 182 return nil
+2 -2
lex/gen.go
··· 468 return packages, nil 469 } 470 471 - func Run(schemas []*Schema, packages []Package) error { 472 - defmap := BuildExtDefMap(schemas, packages) 473 474 for _, pkg := range packages { 475 prefix := pkg.Prefix
··· 468 return packages, nil 469 } 470 471 + func Run(schemas []*Schema, externalSchemas []*Schema, packages []Package) error { 472 + defmap := BuildExtDefMap(append(schemas, externalSchemas...), packages) 473 474 for _, pkg := range packages { 475 prefix := pkg.Prefix