this repo has no description
0
fork

Configure Feed

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

progress on lexgen refactor

+246 -104
+27 -4
cmd/lexgen/flatschema.go cmd/lexgen/flatten.go
··· 105 105 106 106 switch v := def.Inner.(type) { 107 107 case lexicon.SchemaRecord: 108 + fl.Types = append(fl.Types, ft) 108 109 if err := fl.flattenObject(fd, tpath, &v.Record); err != nil { 109 110 return err 110 111 } ··· 117 118 return err 118 119 } 119 120 } 121 + fl.Types = append(fl.Types, ft) 120 122 case lexicon.SchemaProcedure: 121 123 // v.Properties: same as above 122 124 if v.Input != nil && v.Input.Schema != nil { ··· 133 135 return err 134 136 } 135 137 } 138 + fl.Types = append(fl.Types, ft) 136 139 case lexicon.SchemaSubscription: 137 140 // v.Properties: same as above 138 141 if v.Message != nil { ··· 147 150 return fmt.Errorf("subscription with non-union message schema: %T", v.Message.Schema.Inner) 148 151 } 149 152 } 153 + fl.Types = append(fl.Types, ft) 150 154 case lexicon.SchemaObject: 155 + fl.Types = append(fl.Types, ft) 151 156 if err := fl.flattenObject(fd, tpath, &v); err != nil { 152 157 return err 153 158 } ··· 155 160 if !strings.HasPrefix(v.Ref, "#") { 156 161 fl.ExternalRefs[strings.TrimSuffix(v.Ref, "#main")] = true 157 162 } 163 + fl.Types = append(fl.Types, ft) 158 164 case lexicon.SchemaUnion: 159 165 for _, ref := range v.Refs { 160 166 if !strings.HasPrefix(ref, "#") { 161 167 fl.ExternalRefs[strings.TrimSuffix(ref, "#main")] = true 162 168 } 163 169 } 170 + fl.Types = append(fl.Types, ft) 164 171 case lexicon.SchemaArray: 165 172 // flatten the inner item 166 173 tp := slices.Clone(tpath) ··· 173 180 case lexicon.SchemaString, lexicon.SchemaNull, lexicon.SchemaInteger, lexicon.SchemaBoolean, lexicon.SchemaUnknown, lexicon.SchemaBytes: 174 181 // don't emit 175 182 // NOTE: might want to emit some string "knownValue" lists in the future? 176 - return nil 177 183 case lexicon.SchemaCIDLink, lexicon.SchemaBlob: 178 184 // don't emit 179 - return nil 180 185 case lexicon.SchemaToken: 181 186 // pass-through (emit) 187 + fl.Types = append(fl.Types, ft) 182 188 case lexicon.SchemaPermissionSet, lexicon.SchemaPermission: 183 189 // pass-through (emit) 190 + fl.Types = append(fl.Types, ft) 184 191 default: 185 192 return fmt.Errorf("unsupported def type for flattening (%s): %T", fd.Name, def.Inner) 186 193 } 187 194 188 - fl.Types = append(fl.Types, ft) 189 195 return nil 190 196 } 191 197 192 198 func (fl *FlatLexicon) flattenObject(fd *FlatDef, tpath []string, obj *lexicon.SchemaObject) error { 193 - for fname, field := range obj.Properties { 199 + 200 + keys := []string{} 201 + for n := range obj.Properties { 202 + keys = append(keys, n) 203 + } 204 + sort.Strings(keys) 205 + 206 + for _, fname := range keys { 207 + field := obj.Properties[fname] 194 208 tp := slices.Clone(tpath) 195 209 tp = append(tp, fname) 196 210 switch v := field.Inner.(type) { ··· 222 236 } 223 237 return nil 224 238 } 239 + 240 + // Returns the type of any "#main" definition in this file (or else an empty string) 241 + func (fl *FlatLexicon) MainType() string { 242 + main, ok := fl.Defs["main"] 243 + if !ok { 244 + return "" 245 + } 246 + return main.Type 247 + }
+179 -38
cmd/lexgen/generate.go cmd/lexgen/codegen.go
··· 17 17 // one of: "type-decoder", "map-string-any", "json-raw-message" 18 18 UnknownType string 19 19 WarningText string 20 + LegacyMode bool 20 21 } 21 22 22 23 func LegacyConfig() *GenConfig { 23 24 return &GenConfig{ 24 - // XXX RegisterLexiconTypeID: true, 25 - RegisterLexiconTypeID: false, 25 + RegisterLexiconTypeID: true, 26 26 UnknownType: "type-decoder", 27 27 WarningText: "Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.", 28 + LegacyMode: true, 28 29 } 29 30 } 30 31 ··· 49 50 fmt.Fprint(gen.Out, ")\n\n") 50 51 51 52 for _, ft := range gen.Lex.Types { 52 - slog.Info("generating type", "nsid", gen.Lex.NSID, "def", ft.DefName, "path", ft.Path) 53 + slog.Info("generating type", "nsid", gen.Lex.NSID, "def", ft.DefName, "path", ft.Path, "type", ft.Type) 53 54 if err := gen.WriteType(&ft); err != nil { 54 55 return err 55 56 } ··· 58 59 } 59 60 60 61 func (gen *FlatGenerator) pkgName() string { 61 - return nsidPkgName(gen.Lex.NSID) 62 + n := nsidPkgName(gen.Lex.NSID) 63 + if gen.Config.LegacyMode { 64 + switch n { 65 + case "appbsky": 66 + return "bsky" 67 + case "comatproto": 68 + return "atproto" 69 + case "toolsozone": 70 + return "ozone" 71 + case "chatbsky": 72 + return "chat" 73 + } 74 + } 75 + return n 62 76 } 63 77 64 78 func (gen *FlatGenerator) baseName() string { ··· 72 86 73 87 func (gen *FlatGenerator) deps() map[string]bool { 74 88 d := map[string]bool{ 89 + "\"context\"": true, 90 + "\"fmt\"": true, 91 + "\"io\"": true, 92 + "\"bytes\"": true, 93 + "\"encoding/json\"": true, 75 94 "lexutil \"github.com/bluesky-social/indigo/lex/util\"": true, 76 - // TODO: this could be more conditional (the record check is not enough though) 77 - "cbg \"github.com/whyrusleeping/cbor-gen\"": true, 95 + "cbg \"github.com/whyrusleeping/cbor-gen\"": true, 78 96 } 97 + /* TODO: 79 98 for _, t := range gen.Lex.Types { 80 99 switch t.Type { 81 100 case "query", "procedure": ··· 84 103 d["cbg \"github.com/whyrusleeping/cbor-gen\""] = true 85 104 } 86 105 } 106 + */ 87 107 for ext, _ := range gen.Lex.ExternalRefs { 88 108 if strings.HasPrefix(ext, "com.atproto.") { 89 109 d["comatproto \"github.com/bluesky-social/indigo/api/atproto\""] = true ··· 91 111 d["appbsky \"github.com/bluesky-social/indigo/api/bsky\""] = true 92 112 } else if strings.HasPrefix(ext, "tools.ozone.") { 93 113 d["toolsozone \"github.com/bluesky-social/indigo/api/ozone\""] = true 114 + } else if strings.HasPrefix(ext, "chat.bsky.") { 115 + d["chatbsky \"github.com/bluesky-social/indigo/api/chat\""] = true 94 116 } else { 95 - // XXX: handle more mappings; or log/error if missing 117 + // TODO: configurable mappings 118 + slog.Warn("unhandled external reference", "ref", ext) 96 119 } 97 120 } 98 121 return d ··· 104 127 case lexicon.SchemaRecord: 105 128 if gen.Config.RegisterLexiconTypeID { 106 129 fmt.Fprintf(gen.Out, "func init() {\n") 107 - fmt.Fprintf(gen.Out, " lexutil.RegisterType(\"%s#main\", &%s{})", gen.Lex.NSID, gen.baseName()) 130 + fmt.Fprintf(gen.Out, " lexutil.RegisterType(\"%s\", &%s{})", gen.Lex.NSID, gen.baseName()) 108 131 fmt.Fprintf(gen.Out, "}\n\n") 109 132 } 110 133 // HACK: insert record-level description in to object if nil ··· 127 150 case lexicon.SchemaString, lexicon.SchemaInteger, lexicon.SchemaBoolean, lexicon.SchemaUnknown: 128 151 // skip 129 152 case lexicon.SchemaObject: 153 + if gen.Config.RegisterLexiconTypeID && ft.DefName == "main" && len(ft.Path) == 0 { 154 + fmt.Fprintf(gen.Out, "func init() {\n") 155 + fmt.Fprintf(gen.Out, " lexutil.RegisterType(\"%s#main\", &%s{})", gen.Lex.NSID, gen.baseName()) 156 + fmt.Fprintf(gen.Out, "}\n\n") 157 + } 130 158 if err := gen.writeStruct(ft, &v); err != nil { 131 159 return err 132 160 } ··· 150 178 return false 151 179 } 152 180 153 - func (gen *FlatGenerator) fieldType(def *lexicon.SchemaDef, optional bool) (string, error) { 181 + func (gen *FlatGenerator) fieldType(fname string, def *lexicon.SchemaDef, optional bool) (string, error) { 154 182 // NOTE: SchemaObject and SchemaUnion should be handled outside this function; as well as arrays of those types also count 155 183 // TODO: another pass to check for type completeness 156 184 switch v := def.Inner.(type) { ··· 177 205 } 178 206 case lexicon.SchemaBytes: 179 207 // NOTE: not using a pointer for optional 180 - return "[]byte", nil 208 + return "lexutil.LexBytes", nil 181 209 case lexicon.SchemaCIDLink: 182 210 if optional { 183 211 return "*lexutil.LexLink", nil ··· 185 213 return "lexutil.LexLink", nil 186 214 } 187 215 case lexicon.SchemaBlob: 188 - if optional { 216 + if optional || gen.Config.LegacyMode { 189 217 return "*lexutil.LexBlob", nil 190 218 } else { 191 219 return "lexutil.LexBlob", nil 192 220 } 193 221 case lexicon.SchemaArray: 194 - t, err := gen.fieldType(&v.Items, false) 222 + t, err := gen.fieldType(fname, &v.Items, false) 195 223 if err != nil { 196 224 return "", err 197 225 } ··· 200 228 case lexicon.SchemaUnknown: 201 229 switch gen.Config.UnknownType { 202 230 case "type-decoder": 231 + if gen.Config.LegacyMode && (fname == "didDoc" || fname == "plcOp" || fname == "meta") { 232 + if optional { 233 + return "*interface{}", nil 234 + } else { 235 + return "interface{}", nil 236 + } 237 + } 203 238 return "*lexutil.LexiconTypeDecoder", nil 204 239 case "json-raw-message": 205 240 if optional { ··· 226 261 } 227 262 switch dt.Type { 228 263 case "string": 264 + if gen.Config.LegacyMode { 265 + ptr = "*" 266 + } 229 267 return ptr + "string", nil 230 268 case "integer": 231 269 return ptr + "int64", nil ··· 234 272 // TODO: "unknown", "ref", "token", etc 235 273 case "array": 236 274 // TODO: more completeness here (eg, non-object types) 237 - return fmt.Sprintf("[]%s_%s_Elem", gen.baseName(), strings.Title(v.Ref[1:])), nil 275 + structPtr := "" 276 + if gen.Config.LegacyMode { 277 + structPtr = "*" 278 + } 279 + return fmt.Sprintf("[]%s%s_%s_Elem", structPtr, gen.baseName(), strings.Title(v.Ref[1:])), nil 238 280 default: // presumed "object", "union" 281 + if gen.Config.LegacyMode { 282 + ptr = "*" 283 + } 239 284 if v.Ref == "#main" { 240 285 return ptr + gen.baseName(), nil 241 286 } ··· 247 292 t, err := gen.externalRefType(v.Ref) 248 293 if err != nil { 249 294 return "", err 295 + } 296 + if gen.Config.LegacyMode { 297 + ptr = "*" 250 298 } 251 299 return ptr + t, nil 252 300 default: ··· 276 324 } 277 325 278 326 // check if this is actually in the same package (which might not mean the same NSID authority) 279 - if nsidPkgName(nsid) == gen.pkgName() { 327 + if nsidPkgName(nsid) == nsidPkgName(gen.Lex.NSID) { 280 328 if len(parts) == 1 || parts[1] == "main" { 281 329 return nsidBaseName(nsid), nil 282 330 } else { ··· 307 355 fmt.Fprintln(gen.Out, "//") 308 356 } 309 357 } 310 - if obj.Description != nil { 358 + if gen.Lex.Defs[ft.DefName].Type == "procedure" && len(ft.Path) == 1 && ft.Path[0] == "input" { 359 + // TODO: "request body" 360 + fmt.Fprintf(gen.Out, "// %s is the input argument to a %s call.\n", name, gen.Lex.NSID) 361 + } 362 + if (gen.Lex.Defs[ft.DefName].Type == "query" || gen.Lex.Defs[ft.DefName].Type == "procedure") && len(ft.Path) == 1 && ft.Path[0] == "output" { 363 + // TODO: "response body" 364 + fmt.Fprintf(gen.Out, "// %s is the output of a %s call.\n", name, gen.Lex.NSID) 365 + } 366 + skipDesc := false 367 + if gen.Config.LegacyMode && ft.Type == "record" { 368 + skipDesc = true 369 + } 370 + if obj.Description != nil && !skipDesc { 311 371 for _, l := range strings.Split(*obj.Description, "\n") { 312 372 fmt.Fprintf(gen.Out, "// %s\n", l) 313 373 } ··· 322 382 sort.Strings(fieldNames) 323 383 324 384 // if this is a def-level struct, write out type decoder 325 - if len(ft.Path) == 0 { 385 + skipType := false 386 + if gen.Config.LegacyMode { 387 + // TODO: skip $type for all defs in subscription. this isn't robust! 388 + switch gen.Lex.MainType() { 389 + case "subscription": 390 + skipType = true 391 + } 392 + } 393 + if len(ft.Path) == 0 && !skipType { 394 + // TODO: can skip in some more situations? 326 395 fullName := gen.Lex.NSID.String() 327 396 if ft.DefName != "main" { 328 397 fullName += "#" + ft.DefName 329 398 } 330 - fmt.Fprintf(gen.Out, " LexiconTypeID string `json:\"$type\" cborgen:\"$type,const=%s\"`\n", fullName) 399 + omitempty := "" 400 + if gen.Config.LegacyMode && gen.Lex.NSID.String() == "com.atproto.repo.strongRef" { 401 + omitempty = ",omitempty" 402 + } 403 + fmt.Fprintf(gen.Out, " LexiconTypeID string `json:\"$type%s\" cborgen:\"$type,const=%s%s\"`\n", omitempty, fullName, omitempty) 331 404 } 332 405 333 406 for _, fname := range fieldNames { ··· 345 418 switch v := field.Inner.(type) { 346 419 case lexicon.SchemaObject, lexicon.SchemaUnion: 347 420 t = name + "_" + strings.Title(fname) 348 - if optional { 421 + if optional || gen.Config.LegacyMode { 349 422 t = "*" + t 350 423 } 351 424 case lexicon.SchemaArray: 352 425 switch v.Items.Inner.(type) { 353 426 case lexicon.SchemaObject, lexicon.SchemaUnion: 354 - t = "[]" + name + "_" + strings.Title(fname) + "_Elem" 427 + elemPtr := "" 428 + if gen.Config.LegacyMode { 429 + elemPtr = "*" 430 + } 355 431 // NOTE: not using ptr for optional 432 + t = fmt.Sprintf("[]%s%s_%s_Elem", elemPtr, name, strings.Title(fname)) 356 433 default: 357 - t, err = gen.fieldType(&field, optional) 434 + t, err = gen.fieldType(fname, &field, optional) 358 435 if err != nil { 359 436 return err 360 437 } 361 438 } 362 439 default: 363 - t, err = gen.fieldType(&field, optional) 440 + t, err = gen.fieldType(fname, &field, optional) 364 441 if err != nil { 365 442 return err 366 443 } 367 444 } 368 445 446 + cborExtra := "" 447 + // HACK: copied from legacy code for now 448 + if gen.Lex.NSID.String() == "com.atproto.label.defs" && name == "LabelDefs_SelfLabels" && fname == "values" { 449 + cborExtra = ",preservenil" 450 + } 451 + 369 452 desc := defDescription(&field) 370 453 if desc != "" { 371 454 fmt.Fprintf(gen.Out, " // %s: %s\n", fname, desc) 372 455 } 373 456 fmt.Fprintf(gen.Out, " %s %s", strings.ReplaceAll(strings.Title(fname), "-", ""), t) 374 - fmt.Fprintf(gen.Out, " `json:\"%s%s\" cborgen:\"%s%s\"`\n", fname, omitempty, fname, omitempty) 457 + fmt.Fprintf(gen.Out, " `json:\"%s%s\" cborgen:\"%s%s%s\"`\n", fname, omitempty, fname, omitempty, cborExtra) 375 458 } 376 459 fmt.Fprintf(gen.Out, "}\n\n") 377 460 ··· 424 507 refNames = append(refNames, r.FieldName) 425 508 unionRefs[r.FieldName] = r 426 509 } 427 - sort.Strings(refNames) 510 + if !gen.Config.LegacyMode { 511 + sort.Strings(refNames) 512 + } 428 513 429 514 // first print out the union struct type 430 515 if union.Description != nil { ··· 448 533 fmt.Fprintf(gen.Out, " return json.Marshal(t.%s)\n", ref.FieldName) 449 534 fmt.Fprintf(gen.Out, " }\n") 450 535 } 451 - // TODO: better error message here? 452 - fmt.Fprintf(gen.Out, " return nil, fmt.Errorf(\"cannot marshal empty enum\")") 536 + fmt.Fprintf(gen.Out, " return nil, fmt.Errorf(\"can not marshal empty union as JSON\")") 453 537 fmt.Fprintf(gen.Out, "}\n\n") 454 538 455 539 // ... then UnmarshalJSON ··· 466 550 fmt.Fprintf(gen.Out, " return json.Unmarshal(b, t.%s)\n", ref.FieldName) 467 551 } 468 552 fmt.Fprintf(gen.Out, " default:\n") 469 - fmt.Fprintf(gen.Out, " return nil\n") 553 + if union.Closed != nil && *union.Closed { 554 + // TODO: better error message 555 + fmt.Fprintf(gen.Out, " return fmt.Errorf(\"closed unions must match a listed schema\")\n") 556 + } else { 557 + fmt.Fprintf(gen.Out, " return nil\n") 558 + } 470 559 fmt.Fprintf(gen.Out, " }\n") 471 560 fmt.Fprintf(gen.Out, "}\n\n") 472 561 473 - // TODO: bailing out here for; need better logic around whether this is required for a record or not 474 - if true { 562 + if !gen.Config.LegacyMode { 563 + return nil 564 + } 565 + 566 + switch gen.Lex.MainType() { 567 + case "record", "subscription": 568 + // no-op 569 + case "object": 570 + // hacks for legacy serialization 571 + nsid := gen.Lex.NSID.String() 572 + if !(nsid == "app.bsky.richtext.facet" || (nsid == "app.bsky.embed.recordWithMedia" && ft.DefName == "main")) { 573 + return nil 574 + } 575 + default: 475 576 return nil 476 577 } 477 578 478 579 // ... then MarshalCBOR 479 - fmt.Fprintf(gen.Out, "func (t *%s) MarshalCBOR(w io.Writer) error {\n", name) 580 + fmt.Fprintf(gen.Out, "func (t *%s) MarshalCBOR(w io.Writer) error {\n\n", name) 480 581 fmt.Fprintf(gen.Out, " if t == nil {\n") 481 582 fmt.Fprintf(gen.Out, " _, err := w.Write(cbg.CborNull)\n") 482 583 fmt.Fprintf(gen.Out, " return err") ··· 487 588 fmt.Fprintf(gen.Out, " return t.%s.MarshalCBOR(w)\n", ref.FieldName) 488 589 fmt.Fprintf(gen.Out, " }\n") 489 590 } 490 - // TODO: better error message here? 491 - fmt.Fprintf(gen.Out, " return fmt.Errorf(\"cannot cbor marshal empty enum\")") 591 + fmt.Fprintf(gen.Out, " return fmt.Errorf(\"can not marshal empty union as CBOR\")") 492 592 fmt.Fprintf(gen.Out, "}\n\n") 493 593 494 594 // ... then UnmarshalCBOR 495 - fmt.Fprintf(gen.Out, "func (t *%s) UnmarshalCBOR(b []byte) error {\n", name) 496 - fmt.Fprintf(gen.Out, " typ, err := lexutil.TypeExtract(b)\n") 595 + fmt.Fprintf(gen.Out, "func (t *%s) UnmarshalCBOR(r io.Reader) error {\n", name) 596 + fmt.Fprintf(gen.Out, " typ, b, err := lexutil.CborTypeExtractReader(r)\n") 497 597 fmt.Fprintf(gen.Out, " if err != nil {\n") 498 598 fmt.Fprintf(gen.Out, " return err\n") 499 599 fmt.Fprintf(gen.Out, " }\n\n") ··· 516 616 name := gen.baseName() 517 617 518 618 fmt.Fprintf(gen.Out, "// %s calls the XRPC method \"%s\".\n", name, gen.Lex.NSID) 519 - if desc != "" { 619 + if desc != "" && !gen.Config.LegacyMode { 520 620 fmt.Fprintln(gen.Out, "//") 521 621 for _, l := range strings.Split(desc, "\n") { 522 622 fmt.Fprintf(gen.Out, "// %s\n", l) ··· 575 675 if v.Description != nil && *v.Description != "" { 576 676 fmt.Fprintf(gen.Out, "// %s: %s\n", name, *v.Description) 577 677 } 678 + if gen.Config.LegacyMode { 679 + ptr = "" 680 + } 578 681 args = append(args, fmt.Sprintf("%s %sbool", name, ptr)) 579 682 case lexicon.SchemaInteger: 580 683 if v.Description != nil && *v.Description != "" { 581 684 fmt.Fprintf(gen.Out, "// %s: %s\n", name, *v.Description) 685 + } 686 + if gen.Config.LegacyMode { 687 + ptr = "" 582 688 } 583 689 args = append(args, fmt.Sprintf("%s %sint64", name, ptr)) 584 690 case lexicon.SchemaString: ··· 593 699 args = append(args, fmt.Sprintf("%s any", name)) 594 700 case lexicon.SchemaArray: 595 701 if v.Description != nil && *v.Description != "" { 596 - fmt.Fprintf(gen.Out, "// %s[]: %s\n", name, *v.Description) 702 + suffix := "[]" 703 + if gen.Config.LegacyMode { 704 + suffix = "" 705 + } 706 + fmt.Fprintf(gen.Out, "// %s%s: %s\n", name, suffix, *v.Description) 597 707 } 598 708 switch v.Items.Inner.(type) { 599 709 case lexicon.SchemaBoolean: ··· 645 755 fmt.Fprintf(gen.Out, "func %s(%s) ", name, strings.Join(args, ", ")) 646 756 if outputStruct != "" { 647 757 fmt.Fprintf(gen.Out, "(*%s, error) {\n", outputStruct) 648 - fmt.Fprintf(gen.Out, " var out %s\n\n", outputStruct) 758 + fmt.Fprintf(gen.Out, " var out %s\n", outputStruct) 759 + if !gen.Config.LegacyMode { 760 + fmt.Fprintln(gen.Out, "") 761 + } 649 762 doOutParam = "&out" 650 763 returnType = "&out" 651 764 } else if outputBytes { ··· 660 773 paramsArg := "nil" 661 774 if params != nil && len(params.Properties) > 0 { 662 775 paramsArg = "params" 776 + if gen.Config.LegacyMode { 777 + fmt.Fprintln(gen.Out, "") 778 + } 663 779 // TODO: switch to map[string]any 664 780 fmt.Fprintf(gen.Out, " params := map[string]interface{}{}\n") 665 781 } ··· 671 787 fmt.Fprintf(gen.Out, " params[\"%s\"] = %s\n", name, name) 672 788 fmt.Fprintf(gen.Out, " }\n") 673 789 case lexicon.SchemaArray: 674 - fmt.Fprintf(gen.Out, " if len(%s) > 0 {\n", name) 790 + fmt.Fprintf(gen.Out, " if len(%s) != 0 {\n", name) 675 791 fmt.Fprintf(gen.Out, " params[\"%s\"] = %s\n", name, name) 676 792 fmt.Fprintf(gen.Out, " }\n") 677 793 case lexicon.SchemaUnknown: 678 794 fmt.Fprintf(gen.Out, " if %s != nil {\n", name) 679 795 fmt.Fprintf(gen.Out, " params[\"%s\"] = %s\n", name, name) 680 796 fmt.Fprintf(gen.Out, " }\n") 797 + case lexicon.SchemaInteger: 798 + if gen.Config.LegacyMode { 799 + fmt.Fprintf(gen.Out, " if %s != 0 {\n", name) 800 + fmt.Fprintf(gen.Out, " params[\"%s\"] = %s\n", name, name) 801 + fmt.Fprintf(gen.Out, " }\n") 802 + } else { 803 + fmt.Fprintf(gen.Out, " if %s != nil {\n", name) 804 + fmt.Fprintf(gen.Out, " params[\"%s\"] = *%s\n", name, name) 805 + fmt.Fprintf(gen.Out, " }\n") 806 + } 807 + case lexicon.SchemaBoolean: 808 + if gen.Config.LegacyMode { 809 + fmt.Fprintf(gen.Out, " if %s {\n", name) 810 + fmt.Fprintf(gen.Out, " params[\"%s\"] = %s\n", name, name) 811 + fmt.Fprintf(gen.Out, " }\n") 812 + } else { 813 + fmt.Fprintf(gen.Out, " if %s != nil {\n", name) 814 + fmt.Fprintf(gen.Out, " params[\"%s\"] = *%s\n", name, name) 815 + fmt.Fprintf(gen.Out, " }\n") 816 + } 681 817 default: 682 818 fmt.Fprintf(gen.Out, " if %s != nil {\n", name) 683 819 fmt.Fprintf(gen.Out, " params[\"%s\"] = *%s\n", name, name) ··· 687 823 for _, name := range reqParams { 688 824 fmt.Fprintf(gen.Out, " params[\"%s\"] = %s\n", name, name) 689 825 } 690 - fmt.Fprintln(gen.Out, "") 826 + if !gen.Config.LegacyMode { 827 + fmt.Fprintln(gen.Out, "") 828 + } 691 829 692 830 method := "lexutil.Query" 693 831 if isProcedure { ··· 701 839 fmt.Fprintf(gen.Out, " return err\n") 702 840 } 703 841 fmt.Fprintf(gen.Out, " }\n") 842 + if gen.Config.LegacyMode { 843 + fmt.Fprintln(gen.Out, "") 844 + } 704 845 if returnType != "" { 705 846 fmt.Fprintf(gen.Out, " return %s, nil\n", returnType) 706 847 } else {
+40 -62
cmd/lexgen/main.go
··· 7 7 "fmt" 8 8 "go/format" 9 9 "io/fs" 10 - "log/slog" 11 10 "os" 12 11 "path" 13 12 "path/filepath" ··· 37 36 Version: versioninfo.Short(), 38 37 } 39 38 app.Commands = []*cli.Command{ 40 - cmdGenerate, 41 - cmdDev, 39 + cmdLegacy, 40 + cmdGen, 42 41 } 43 42 return app.Run(context.Background(), args) 44 43 } 45 44 46 - var cmdGenerate = &cli.Command{ 47 - Name: "generate", 48 - Usage: "check schema syntax, best practices, and style", 45 + var cmdLegacy = &cli.Command{ 46 + Name: "legacy", 47 + Usage: "generate code with legacy behaviors", 48 + ArgsUsage: `<file-or-dir>*`, 49 + Flags: []cli.Flag{ 50 + &cli.StringFlag{ 51 + Name: "lexicons-dir", 52 + Value: "./lexicons/", 53 + Usage: "base directory for project Lexicon files", 54 + Sources: cli.EnvVars("LEXICONS_DIR"), 55 + }, 56 + &cli.StringFlag{ 57 + Name: "output-dir", 58 + Value: "./lexgen-output/", 59 + Usage: "base directory for output packages", 60 + Sources: cli.EnvVars("OUTPUT_DIR"), 61 + }, 62 + &cli.BoolFlag{ 63 + Name: "legacy-mode", 64 + Value: true, 65 + }, 66 + }, 67 + Action: runGen, 68 + } 69 + 70 + var cmdGen = &cli.Command{ 71 + Name: "gen", 72 + Usage: "generate code for lexicons", 49 73 ArgsUsage: `<file-or-dir>*`, 50 74 Flags: []cli.Flag{ 51 75 &cli.StringFlag{ ··· 61 85 Sources: cli.EnvVars("OUTPUT_DIR"), 62 86 }, 63 87 }, 64 - Action: runGenerate, 88 + Action: runGen, 65 89 } 66 90 67 - func runGenerate(ctx context.Context, cmd *cli.Command) error { 91 + func runGen(ctx context.Context, cmd *cli.Command) error { 68 92 paths := cmd.Args().Slice() 69 93 if !cmd.Args().Present() { 70 94 paths = []string{cmd.String("lexicons-dir")} ··· 84 108 } 85 109 } 86 110 87 - slog.Debug("starting lint run") 88 111 for _, p := range paths { 89 112 finfo, err := os.Stat(p) 90 113 if err != nil { ··· 138 161 return fmt.Errorf("internal codegen flattening error (%s): %w", p, err) 139 162 } 140 163 141 - buf := new(bytes.Buffer) 164 + cfg := &GenConfig{} 165 + if cmd.Bool("legacy-mode") { 166 + cfg = LegacyConfig() 167 + } 142 168 169 + buf := new(bytes.Buffer) 143 170 gen := FlatGenerator{ 144 - Config: LegacyConfig(), 171 + Config: cfg, 145 172 Lex: flat, 146 173 Cat: cat, 147 174 Out: buf, ··· 155 182 return err 156 183 } 157 184 158 - fixImports := false 185 + // TODO: this gets really slow if any imports are missing. should make this a CLI arg 186 + fixImports := true 159 187 if fixImports { 160 188 fmtOpts := imports.Options{ 161 189 Comments: true, ··· 175 203 return os.WriteFile(outPath, formatted, 0644) 176 204 } 177 205 } 178 - 179 - var cmdDev = &cli.Command{ 180 - Name: "dev", 181 - ArgsUsage: `<file>`, 182 - Flags: []cli.Flag{ 183 - &cli.StringFlag{ 184 - Name: "lexicons-dir", 185 - Value: "./lexicons/", 186 - Usage: "base directory for project Lexicon files", 187 - Sources: cli.EnvVars("LEXICONS_DIR"), 188 - }, 189 - }, 190 - Action: runDev, 191 - } 192 - 193 - func runDev(ctx context.Context, cmd *cli.Command) error { 194 - if !cmd.Args().Present() { 195 - return fmt.Errorf("require one or more paths") 196 - } 197 - 198 - b, err := os.ReadFile(cmd.Args().First()) 199 - if err != nil { 200 - return err 201 - } 202 - 203 - var sf lexicon.SchemaFile 204 - err = json.Unmarshal(b, &sf) 205 - if err == nil { 206 - err = sf.FinishParse() 207 - } 208 - if err != nil { 209 - return err 210 - } 211 - 212 - flat, err := FlattenSchemaFile(&sf) 213 - if err != nil { 214 - return err 215 - } 216 - 217 - cat := lexicon.NewBaseCatalog() 218 - gen := FlatGenerator{ 219 - Config: &GenConfig{ 220 - RegisterLexiconTypeID: true, 221 - }, 222 - Cat: &cat, 223 - Lex: flat, 224 - Out: os.Stdout, 225 - } 226 - return gen.WriteLexicon() 227 - }