this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

start lexgen refactor

+137 -177
-26
cmd/lexgen/bsky.json
··· 1 - [ 2 - { 3 - "package": "bsky", 4 - "prefix": "app.bsky", 5 - "outdir": "api/bsky", 6 - "import": "github.com/bluesky-social/indigo/api/bsky" 7 - }, 8 - { 9 - "package": "atproto", 10 - "prefix": "com.atproto", 11 - "outdir": "api/atproto", 12 - "import": "github.com/bluesky-social/indigo/api/atproto" 13 - }, 14 - { 15 - "package": "chat", 16 - "prefix": "chat.bsky", 17 - "outdir": "api/chat", 18 - "import": "github.com/bluesky-social/indigo/api/chat" 19 - }, 20 - { 21 - "package": "ozone", 22 - "prefix": "tools.ozone", 23 - "outdir": "api/ozone", 24 - "import": "github.com/bluesky-social/indigo/api/ozone" 25 - } 26 - ]
+14
cmd/lexgen/codegen.go
··· 1 + package main 2 + 3 + import ( 4 + "io" 5 + ) 6 + 7 + type GenConfig struct { 8 + } 9 + 10 + type Generator struct { 11 + Config *GenConfig 12 + Lex *FlatLexicon 13 + Out io.Writer 14 + }
+42
cmd/lexgen/flatschema.go
··· 1 + package main 2 + 3 + import ( 4 + "github.com/bluesky-social/indigo/atproto/lexicon" 5 + "github.com/bluesky-social/indigo/atproto/syntax" 6 + ) 7 + 8 + // Intermediate representation of a complete lexicon schema file, containing one or more definitions. 9 + type FlatLexicon struct { 10 + NSID syntax.NSID 11 + ExternalRefs map[string]bool // NSID with optional ref 12 + SelfRefs map[string]bool // def names 13 + Defs map[string]FlatDef 14 + Types []FlatType 15 + } 16 + 17 + // Minimal context about an individual top-level schema definition: just the short name and schema type. 18 + type FlatDef struct { 19 + Name string 20 + Type string 21 + } 22 + 23 + // An individual "type definition", which is a small unit of schema definition that corresponds to a named unit of generated code. For example, a struct or API endpoint. 24 + type FlatType struct { 25 + // the short name of the schema def that this type is under 26 + DefName string 27 + Path []string 28 + Type string 29 + Schema *lexicon.SchemaDef 30 + } 31 + 32 + func FlattenSchemaFile(sf *lexicon.SchemaFile) (*FlatLexicon, error) { 33 + // XXX 34 + } 35 + 36 + func (fl *FlatLexicon) flattenDef(name string, def *lexicon.SchemaDef) error { 37 + // XXX 38 + } 39 + 40 + func (fl *FlatLexicon) flattenType(fd *FlatDef, tpath []string, def *lexicon.SchemaDef) error { 41 + // XXX 42 + }
+81 -151
cmd/lexgen/main.go
··· 1 1 package main 2 2 3 3 import ( 4 - "errors" 4 + "context" 5 + "encoding/json" 5 6 "fmt" 6 7 "io/fs" 8 + "log/slog" 7 9 "os" 10 + "path" 8 11 "path/filepath" 9 - "strings" 10 12 11 - "github.com/bluesky-social/indigo/lex" 12 - "github.com/urfave/cli/v2" 13 - ) 13 + _ "github.com/joho/godotenv/autoload" 14 14 15 - func findSchemas(dir string, out []string) ([]string, error) { 16 - err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { 17 - if err != nil { 18 - return err 19 - } 15 + "github.com/bluesky-social/indigo/atproto/lexicon" 20 16 21 - if info.IsDir() { 22 - return nil 23 - } 24 - 25 - if strings.HasSuffix(path, ".json") { 26 - out = append(out, path) 27 - } 17 + "github.com/earthboundkid/versioninfo/v2" 18 + "github.com/urfave/cli/v3" 19 + ) 28 20 29 - return nil 30 - }) 31 - if err != nil { 32 - return out, err 21 + func main() { 22 + if err := run(os.Args); err != nil { 23 + fmt.Fprintf(os.Stderr, "error: %v\n", err) 24 + os.Exit(-1) 33 25 } 34 - 35 - return out, nil 36 - 37 26 } 38 27 39 - // for direct .json lexicon files or directories containing lexicon .json files, get one flat list of all paths to .json files 40 - func expandArgs(args []string) ([]string, error) { 41 - var out []string 42 - for _, a := range args { 43 - st, err := os.Stat(a) 44 - if err != nil { 45 - return nil, err 46 - } 47 - if st.IsDir() { 48 - out, err = findSchemas(a, out) 49 - if err != nil { 50 - return nil, err 51 - } 52 - } else if strings.HasSuffix(a, ".json") { 53 - out = append(out, a) 54 - } 55 - } 28 + func run(args []string) error { 56 29 57 - return out, nil 30 + app := cli.Command{ 31 + Name: "lexgen", 32 + Usage: "AT lexicon code generation for Go", 33 + //Description: "", 34 + Version: versioninfo.Short(), 35 + } 36 + app.Commands = []*cli.Command{ 37 + cmdGenerate, 38 + } 39 + return app.Run(context.Background(), args) 58 40 } 59 41 60 - func main() { 61 - app := cli.NewApp() 62 - 63 - app.Flags = []cli.Flag{ 42 + var cmdGenerate = &cli.Command{ 43 + Name: "generate", 44 + Usage: "check schema syntax, best practices, and style", 45 + ArgsUsage: `<file-or-dir>*`, 46 + Flags: []cli.Flag{ 64 47 &cli.StringFlag{ 65 - Name: "outdir", 66 - }, 67 - &cli.BoolFlag{ 68 - Name: "gen-server", 48 + Name: "lexicons-dir", 49 + Value: "./lexicons/", 50 + Usage: "base directory for project Lexicon files", 51 + Sources: cli.EnvVars("LEXICONS_DIR"), 69 52 }, 70 53 &cli.BoolFlag{ 71 - Name: "gen-handlers", 72 - }, 73 - &cli.StringSliceFlag{ 74 - Name: "types-import", 54 + Name: "json", 55 + Usage: "output structured JSON", 75 56 }, 76 - &cli.StringSliceFlag{ 77 - Name: "external-lexicons", 78 - }, 79 - &cli.StringFlag{ 80 - Name: "package", 81 - Value: "schemagen", 82 - }, 83 - &cli.StringFlag{ 84 - Name: "build", 85 - Value: "", 86 - }, 87 - &cli.StringFlag{ 88 - Name: "build-file", 89 - Value: "", 90 - }, 91 - } 92 - app.Action = func(cctx *cli.Context) error { 93 - paths, err := expandArgs(cctx.Args().Slice()) 57 + }, 58 + Action: runGenerate, 59 + } 60 + 61 + func runGenerate(ctx context.Context, cmd *cli.Command) error { 62 + paths := cmd.Args().Slice() 63 + if !cmd.Args().Present() { 64 + paths = []string{cmd.String("lexicons-dir")} 65 + _, err := os.Stat(paths[0]) 94 66 if err != nil { 95 - return err 67 + return fmt.Errorf("no path arguments specified and default lexicon directory not found\n%w", err) 96 68 } 69 + } 97 70 98 - var schemas []*lex.Schema 99 - for _, arg := range paths { 100 - if strings.HasSuffix(arg, "com/atproto/temp/importRepo.json") { 101 - fmt.Printf("skipping schema: %s\n", arg) 102 - continue 103 - } 104 - s, err := lex.ReadSchema(arg) 105 - if err != nil { 106 - return fmt.Errorf("failed to read file %q: %w", arg, err) 107 - } 71 + // TODO: load up entire directory in to a catalog? or have a "linter" struct? 108 72 109 - schemas = append(schemas, s) 110 - } 111 - 112 - externalPaths, err := expandArgs(cctx.StringSlice("external-lexicons")) 73 + slog.Debug("starting lint run") 74 + for _, p := range paths { 75 + finfo, err := os.Stat(p) 113 76 if err != nil { 114 - return err 77 + return fmt.Errorf("failed loading %s: %w", p, err) 115 78 } 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) 79 + if finfo.IsDir() { 80 + if err := filepath.WalkDir(p, func(fp string, d fs.DirEntry, err error) error { 81 + if d.IsDir() || path.Ext(fp) != ".json" { 82 + return nil 83 + } 84 + return blah(ctx, cmd, fp) 85 + }); err != nil { 86 + return err 121 87 } 122 - 123 - externalSchemas = append(externalSchemas, s) 88 + continue 124 89 } 125 - 126 - buildLiteral := cctx.String("build") 127 - buildPath := cctx.String("build-file") 128 - var packages []lex.Package 129 - if buildLiteral != "" { 130 - if buildPath != "" { 131 - return errors.New("must not set both --build and --build-file") 132 - } 133 - packages, err = lex.ParsePackages([]byte(buildLiteral)) 134 - if err != nil { 135 - return fmt.Errorf("--build error, %w", err) 136 - } 137 - if len(packages) == 0 { 138 - return errors.New("--build must specify at least one Package{}") 139 - } 140 - } else if buildPath != "" { 141 - blob, err := os.ReadFile(buildPath) 142 - if err != nil { 143 - return fmt.Errorf("--build-file error, %w", err) 144 - } 145 - packages, err = lex.ParsePackages(blob) 146 - if err != nil { 147 - return fmt.Errorf("--build-file error, %w", err) 148 - } 149 - if len(packages) == 0 { 150 - return errors.New("--build-file must specify at least one Package{}") 151 - } 152 - } else { 153 - return errors.New("need exactly one of --build or --build-file") 90 + if err := blah(ctx, cmd, p); err != nil { 91 + return err 154 92 } 155 - 156 - if cctx.Bool("gen-server") { 157 - pkgname := cctx.String("package") 158 - outdir := cctx.String("outdir") 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") 166 - importmap := make(map[string]string) 167 - for _, p := range paths { 168 - parts := strings.Split(p, ":") 169 - importmap[parts[0]] = parts[1] 170 - } 171 - 172 - handlers := cctx.Bool("gen-handlers") 93 + } 94 + return nil 95 + } 173 96 174 - if err := lex.CreateHandlerStub(pkgname, importmap, outdir, schemas, handlers); err != nil { 175 - return err 176 - } 97 + func blah(ctx context.Context, cmd *cli.Command, p string) error { 98 + b, err := os.ReadFile(p) 99 + if err != nil { 100 + return err 101 + } 177 102 178 - } else { 179 - return lex.Run(schemas, externalSchemas, packages) 180 - } 103 + // parse file regularly 104 + // TODO: use json/v2 when available for case-sensitivity 105 + var sf lexicon.SchemaFile 181 106 182 - return nil 107 + // two-part parsing before looking at errors 108 + err = json.Unmarshal(b, &sf) 109 + if err == nil { 110 + err = sf.FinishParse() 111 + } 112 + if err != nil { 113 + return err 183 114 } 184 - 185 - app.RunAndExitOnError() 115 + return nil 186 116 }