├── .github ├── FUNDING.yml └── workflows │ ├── goreleaser.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── cmd ├── buildinfo.go └── root.go ├── config └── config.go ├── examples ├── abstract │ ├── excluded.go │ ├── index.ts │ ├── iota.go │ └── misc.go ├── bookstore │ ├── author.go │ ├── book.go │ └── index.ts ├── directive │ ├── directive.go │ └── index.ts ├── embed │ ├── embed.go │ ├── index.ts │ └── types.go ├── emit │ ├── custom.go │ ├── excluded.go │ └── index.ts ├── generic │ ├── generic.go │ └── index.ts ├── generic_any │ ├── any.go │ └── index.ts ├── globalconfig │ └── globalconfig.go ├── inheritance │ ├── index.ts │ └── inheritance.go ├── interface │ ├── index.ts │ └── interface.go ├── noComments │ ├── index.ts │ └── noComments.go ├── preserveTypeComments │ ├── index.ts │ └── preserveTypeComments.go ├── rune │ ├── index.ts │ └── rune.go ├── simple │ ├── index.ts │ └── simple.go └── yaml │ ├── index.ts │ └── yaml.go ├── go.mod ├── go.sum ├── goreleaser.yml ├── main.go ├── tygo.yaml └── tygo ├── config.go ├── convert_string.go ├── fixtures_test.go ├── generator.go ├── iota.go ├── package_generator.go ├── testdata └── fixtures │ ├── directive.md │ ├── emit.md │ ├── generic.md │ ├── inheritance.md │ └── simple.md ├── write.go ├── write_comment.go ├── write_headers.go └── write_toplevel.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: gzuidhof 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/goreleaser.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | goreleaser: 13 | runs-on: ubuntu-latest 14 | env: 15 | flags: "" 16 | steps: 17 | - if: ${{ !startsWith(github.ref, 'refs/tags/v') }} 18 | run: echo "flags=--snapshot" >> $GITHUB_ENV # See https://github.com/goreleaser/goreleaser-action/issues/387 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | - name: Set up Go 24 | uses: actions/setup-go@v5 25 | with: 26 | go-version: "^1.18" 27 | - name: Run GoReleaser 28 | uses: goreleaser/goreleaser-action@v6 29 | with: 30 | distribution: goreleaser 31 | version: '~> v2' 32 | args: release --clean ${{ env.flags }} 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test Tygo 2 | on: 3 | pull_request: 4 | push: 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | go-version: 12 | - 1.22.x 13 | steps: 14 | - name: checkout 15 | uses: actions/checkout@v4 16 | - name: install 17 | uses: actions/setup-go@v5 18 | with: 19 | go-version: '${{ matrix.go-version }}' 20 | - name: vet 21 | run: go vet ./... 22 | - name: test 23 | run: go test -v -race ./... -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | examples/time 18 | examples/tygo 19 | examples/http 20 | 21 | dist/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.2.4 2 | * Add support for `fallback_type`, which allows one to specify the type that should be used for unknown types (defaults to `any`). 3 | 4 | # 0.2.3 5 | * Add support for `include_files` in the config, which allows one to specify the only files that should be included. 6 | 7 | # 0.2.2 8 | * Add support for `readonly` fields. 9 | 10 | # 0.2.1 11 | * Add support for single `IndexExpr` in type alias, such as `type X = Y[string]`. 12 | 13 | # 0.2.0 14 | 15 | * Support for generic types for Golang 1.18 and beyond. 16 | 17 | # 0.1.2 18 | 19 | * You can now mark pointer type fields as required by adding `,required` to the struct field tag. 20 | 21 | # 0.1.1 22 | 23 | * You can now exclude fields with `tstype:"-"`. 24 | 25 | # 0.1.0 26 | 27 | First public release. 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Guido Zuidhof 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎑 tygo 2 | 3 | Tygo is a tool for generating Typescript typings from Golang source files that just works. 4 | 5 | It preserves comments, understands constants and also supports non-struct `type` expressions. It's perfect for generating equivalent types for a Golang REST API to be used in your front-end codebase. 6 | 7 | **🚀 Supports Golang 1.18 generic types and struct inheritance** 8 | 9 | ## Installation 10 | 11 | ```shell 12 | go install github.com/gzuidhof/tygo@latest 13 | ``` 14 | 15 | ## Example 16 | 17 | _Golang input file_ 18 | 19 | ```go 20 | // Comments are kept :) 21 | type ComplexType map[string]map[uint16]*uint32 22 | 23 | type UserRole = string 24 | const ( 25 | UserRoleDefault UserRole = "viewer" 26 | UserRoleEditor UserRole = "editor" // Line comments are also kept 27 | ) 28 | 29 | type UserEntry struct { 30 | // Instead of specifying `tstype` we could also declare the typing 31 | // for uuid.NullUUID in the config file. 32 | ID uuid.NullUUID `json:"id" tstype:"string | null"` 33 | 34 | Preferences map[string]struct { 35 | Foo uint32 `json:"foo"` 36 | // An unknown type without a `tstype` tag or mapping in the config file 37 | // becomes `any` 38 | Bar uuid.UUID `json:"bar"` 39 | } `json:"prefs"` 40 | 41 | MaybeFieldWithStar *string `json:"address"` 42 | Nickname string `json:"nickname,omitempty"` 43 | Role UserRole `json:"role"` 44 | CreatedAt time.Time `json:"created_at,omitzero"` 45 | 46 | Complex ComplexType `json:"complex"` 47 | unexported bool // Unexported fields are omitted 48 | Ignored bool `tstype:"-"` // Fields with - are omitted too 49 | } 50 | 51 | type ListUsersResponse struct { 52 | Users []UserEntry `json:"users"` 53 | } 54 | ``` 55 | 56 | _Typescript output_ 57 | 58 | ```typescript 59 | /** 60 | * Comments are kept :) 61 | */ 62 | export type ComplexType = { 63 | [key: string]: { 64 | [key: number /* uint16 */]: number /* uint32 */ | undefined; 65 | }; 66 | }; 67 | export type UserRole = string; 68 | export const UserRoleDefault: UserRole = "viewer"; 69 | export const UserRoleEditor: UserRole = "editor"; // Line comments are also kept 70 | export interface UserEntry { 71 | /** 72 | * Instead of specifying `tstype` we could also declare the typing 73 | * for uuid.NullUUID in the config file. 74 | */ 75 | id: string | null; 76 | prefs: { 77 | [key: string]: { 78 | foo: number /* uint32 */; 79 | /** 80 | * An unknown type without a `tstype` tag or mapping in the config file 81 | * becomes `any` 82 | */ 83 | bar: any /* uuid.UUID */; 84 | }; 85 | }; 86 | address?: string; 87 | nickname?: string; 88 | role: UserRole; 89 | created_at?: string /* RFC3339 */; 90 | complex: ComplexType; 91 | } 92 | export interface ListUsersResponse { 93 | users: UserEntry[]; 94 | } 95 | ``` 96 | 97 | For a real baptism by fire example, [here is a Gist with output for the Go built-in `net/http` and `time` package](https://gist.github.com/gzuidhof/7e192a2f33d8a4f5bde5b77fb2c5048c). 98 | 99 | ## Usage 100 | 101 | ### Option A: CLI (recommended) 102 | 103 | Create a file `tygo.yaml` in which you specify which packages are to be converted and any special type mappings you want to add. 104 | 105 | ```yaml 106 | packages: 107 | - path: "github.com/gzuidhof/tygo/examples/bookstore" 108 | type_mappings: 109 | time.Time: "string /* RFC3339 */" 110 | null.String: "null | string" 111 | null.Bool: "null | boolean" 112 | uuid.UUID: "string /* uuid */" 113 | uuid.NullUUID: "null | string /* uuid */" 114 | ``` 115 | 116 | Then run 117 | 118 | ```shell 119 | tygo generate 120 | ``` 121 | 122 | The output Typescript file will be next to the Go source files. 123 | 124 | ### Option B: Library-mode 125 | 126 | ```go 127 | config := &tygo.Config{ 128 | Packages: []*tygo.PackageConfig{ 129 | &tygo.PackageConfig{ 130 | Path: "github.com/gzuidhof/tygo/examples/bookstore", 131 | }, 132 | }, 133 | } 134 | gen := tygo.New(config) 135 | err := gen.Generate() 136 | ``` 137 | 138 | ## Config 139 | 140 | ```yaml 141 | # You can specify default mappings that will apply to all packages. 142 | type_mappings: 143 | time.Time: "string /* RFC3339 */" 144 | 145 | # You can specify more than one package 146 | packages: 147 | # The package path just like you would import it in Go 148 | - path: "github.com/my/package" 149 | 150 | # Where this output should be written to. 151 | # If you specify a folder it will be written to a file `index.ts` within that folder. By default it is written into the Golang package folder. 152 | output_path: "webapp/api/types.ts" 153 | 154 | # Customize the indentation (use \t if you want tabs) 155 | indent: " " 156 | 157 | # Specify your own custom type translations, useful for custom types, `time.Time` and `null.String`. 158 | # By default unrecognized types will be `any`. 159 | # A mapping specified here will override one specified globally. 160 | type_mappings: 161 | time.Time: "string" 162 | my.Type: "SomeType" 163 | 164 | # This content will be put at the top of the output Typescript file, useful for importing custom types. 165 | frontmatter: | 166 | "import {SomeType} from "../lib/sometype.ts" 167 | 168 | # Filenames of Go source files that should not be included 169 | # in the output. 170 | exclude_files: 171 | - "private_stuff.go" 172 | 173 | # Package that the generates Typescript types should extend. This is useful when 174 | # attaching your types to a generic ORM. 175 | extends: "SomeType" 176 | ``` 177 | 178 | See also the source file [tygo/config.go](./tygo/config.go). 179 | 180 | ## Type hints through tagging 181 | 182 | You can tag struct fields with `tstype` to specify their output Typescript type. 183 | 184 | ### Custom type mapping 185 | 186 | ```golang 187 | // Golang input 188 | 189 | type Book struct { 190 | Title string `json:"title"` 191 | Genre string `json:"genre" tstype:"'novel' | 'crime' | 'fantasy'"` 192 | } 193 | ``` 194 | 195 | ```typescript 196 | // Typescript output 197 | 198 | export interface Book { 199 | title: string; 200 | genre: "novel" | "crime" | "fantasy"; 201 | } 202 | ``` 203 | 204 | **Alternative** 205 | 206 | You could use the `frontmatter` field in the config to inject `export type Genre = "novel" | "crime" | "fantasy"` at the top of the file, and use `tstype:"Genre"`. I personally prefer that as we may use the `Genre` type more than once. 207 | 208 | **`tygo:emit` directive** 209 | 210 | Another way to generate types that cannot be directly represented in Go is to use a `//tygo:emit` directive to 211 | directly emit literal TS code. 212 | The directive can be used in two ways. A `tygo:emit` directive on a struct will emit the remainder of the directive 213 | text before the struct. 214 | ```golang 215 | // Golang input 216 | 217 | //tygo:emit export type Genre = "novel" | "crime" | "fantasy" 218 | type Book struct { 219 | Title string `json:"title"` 220 | Genre string `json:"genre" tstype:"Genre"` 221 | } 222 | ``` 223 | 224 | ```typescript 225 | export type Genre = "novel" | "crime" | "fantasy" 226 | 227 | export interface Book { 228 | title: string; 229 | genre: Genre; 230 | } 231 | ``` 232 | 233 | A `//tygo:emit` directive on a string var will emit the contents of the var, useful for multi-line content. 234 | ```golang 235 | //tygo:emit 236 | var _ = `export type StructAsTuple=[ 237 | a:number, 238 | b:number, 239 | c:string, 240 | ] 241 | ` 242 | type CustomMarshalled struct { 243 | Content []StructAsTuple `json:"content"` 244 | } 245 | ``` 246 | 247 | ```typescript 248 | export type StructAsTuple=[ 249 | a:number, 250 | b:number, 251 | c:string, 252 | ] 253 | 254 | export interface CustomMarshalled { 255 | content: StructAsTuple[]; 256 | } 257 | 258 | ``` 259 | 260 | Generating types this way is particularly useful for tuple types, because a comma cannot be used in the `tstype` tag. 261 | 262 | ### Required fields 263 | 264 | Pointer type fields usually become optional in the Typescript output, but sometimes you may want to require it regardless. 265 | 266 | You can add `,required` to the `tstype` tag to mark a pointer type as required. 267 | 268 | ```golang 269 | // Golang input 270 | type Nicknames struct { 271 | Alice *string `json:"alice"` 272 | Bob *string `json:"bob" tstype:"BobCustomType,required"` 273 | Charlie *string `json:"charlie" tstype:",required"` 274 | } 275 | ``` 276 | 277 | ```typescript 278 | // Typescript output 279 | export interface Nicknames { 280 | alice?: string; 281 | bob: BobCustomType; 282 | charlie: string; 283 | } 284 | ``` 285 | 286 | ### Readonly fields 287 | 288 | Sometimes a field should be immutable, you can add `,readonly` to the `tstype` tag to mark a field as `readonly`. 289 | 290 | ```golang 291 | // Golang input 292 | type Cat struct { 293 | Name string `json:"name,readonly"` 294 | Owner string `json:"owner"` 295 | } 296 | ``` 297 | 298 | ```typescript 299 | // Typescript output 300 | export interface Cat { 301 | readonly name: string; 302 | owner: string; 303 | } 304 | ``` 305 | 306 | ## Inheritance 307 | 308 | Tygo supports interface inheritance. To extend an `inlined` struct, use the tag `tstype:",extends"` on struct fields you wish to extend. Only `struct` types can be extended. 309 | 310 | Struct pointers are optionally extended using `Partial`. To mark these structs as required, use the tag `tstype:",extends,required"`. 311 | 312 | Named `struct fields` can also be extended. 313 | 314 | Example usage [here](examples/inheritance) 315 | 316 | ```go 317 | // Golang input 318 | import "example.com/external" 319 | 320 | type Base struct { 321 | Name string `json:"name"` 322 | } 323 | 324 | type Base2[T string | int] struct { 325 | ID T `json:"id"` 326 | } 327 | 328 | type OptionalPtr struct { 329 | Field string `json:"field"` 330 | } 331 | 332 | type Other[T int] struct { 333 | *Base ` tstype:",extends,required"` 334 | Base2[T] ` tstype:",extends"` 335 | *OptionalPtr ` tstype:",extends"` 336 | external.AnotherStruct ` tstype:",extends"` 337 | OtherValue string ` json:"other_value"` 338 | } 339 | ``` 340 | 341 | ```typescript 342 | // Typescript output 343 | export interface Base { 344 | name: string; 345 | } 346 | 347 | export interface Base2 { 348 | id: T; 349 | } 350 | 351 | export interface OptionalPtr { 352 | field: string; 353 | } 354 | 355 | export interface Other 356 | extends Base, 357 | Base2, 358 | Partial, 359 | external.AnotherStruct { 360 | other_value: string; 361 | } 362 | ``` 363 | 364 | ## Generics 365 | 366 | Tygo supports generic types (Go version >= 1.18) out of the box. 367 | 368 | ```go 369 | // Golang input 370 | type UnionType interface { 371 | uint64 | string 372 | } 373 | 374 | type ABCD[A, B string, C UnionType, D int64 | bool] struct { 375 | A A `json:"a"` 376 | B B `json:"b"` 377 | C C `json:"c"` 378 | D D `json:"d"` 379 | } 380 | ``` 381 | 382 | ```typescript 383 | // Typescript output 384 | export type UnionType = number /* uint64 */ | string; 385 | 386 | export interface ABCD< 387 | A extends string, 388 | B extends string, 389 | C extends UnionType, 390 | D extends number /* int64 */ | boolean 391 | > { 392 | a: A; 393 | b: B; 394 | c: C; 395 | d: D; 396 | } 397 | ``` 398 | 399 | ## YAML support 400 | 401 | Tygo supports generating typings for YAML-serializable objects that can be understood by Go apps. 402 | 403 | By default, Tygo will respect `yaml` Go struct tags, in addition to `json`, but it will not apply any transformations to untagged fields. 404 | However, the default behavior of the popular `gopkg.in/yaml.v2` package for Go structs without tags is to downcase the struct field names. 405 | To emulate this behavior, one can use the `flavor` configuration option: 406 | 407 | ```yaml 408 | packages: 409 | - path: "github.com/my/package" 410 | output_path: "webapp/api/types.ts" 411 | flavor: "yaml" 412 | ``` 413 | 414 | ```go 415 | // Golang input 416 | type Foo struct { 417 | TaggedField string `yaml:"custom_field_name_in_yaml"` 418 | UntaggedField string 419 | } 420 | ``` 421 | 422 | ```typescript 423 | // Typescript output 424 | export interface Foo { 425 | custom_field_name_in_yaml: string; 426 | untaggedfield: string; 427 | } 428 | ``` 429 | 430 | ## Related projects 431 | 432 | - [**typescriptify-golang-structs**](https://github.com/tkrajina/typescriptify-golang-structs): Probably the most popular choice. The downside of this package is that it relies on reflection rather than parsing, which means that certain things can't be kept such as comments without adding a bunch of tags to your structs. The CLI generates a Go file which is then executed and reflected on. The library requires you to manually specify all types that should be converted. 433 | - [**go2ts**](https://github.com/StirlingMarketingGroup/go2ts): A transpiler with a web interface, this project can be seen as an evolution of this project. It's perfect for quick one-off transpilations. There is no CLI, no support for `const` and there are no ways to customize the output. 434 | 435 | **If `tygo` is useful for your project, consider leaving a star.** 436 | 437 | ## License 438 | 439 | [MIT](./LICENSE) 440 | -------------------------------------------------------------------------------- /cmd/buildinfo.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | // Field injected by goreleaser 9 | var ( 10 | version = "" 11 | commitDate = "date unknown" 12 | commit = "" 13 | ) 14 | 15 | func Version() string { 16 | return version 17 | } 18 | 19 | func CommitDate() string { 20 | return commitDate 21 | } 22 | 23 | func Commit() string { 24 | return commit 25 | } 26 | 27 | func Target() string { 28 | return runtime.GOOS 29 | } 30 | 31 | func FullVersion() string { 32 | return fmt.Sprintf("%s %s/%s %s (%s) %s", 33 | version, runtime.GOOS, runtime.GOARCH, runtime.Version(), commitDate, commit) 34 | } 35 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/gzuidhof/tygo/config" 9 | "github.com/gzuidhof/tygo/tygo" 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | func Execute() { 14 | rootCmd := &cobra.Command{ 15 | Use: "tygo", 16 | Short: "Tool for generating Typescript from Go types", 17 | Long: `Tygo generates Typescript interfaces and constants from Go files by parsing them.`, 18 | } 19 | 20 | rootCmd.PersistentFlags(). 21 | String("config", "tygo.yaml", "config file to load (default is tygo.yaml in the current folder)") 22 | rootCmd.Version = FullVersion() 23 | rootCmd.PersistentFlags().BoolP("debug", "D", false, "Debug mode (prints debug messages)") 24 | 25 | rootCmd.AddCommand(&cobra.Command{ 26 | Use: "generate", 27 | Short: "Generate and write to disk", 28 | Run: generate, 29 | }) 30 | 31 | if err := rootCmd.Execute(); err != nil { 32 | fmt.Println(err) 33 | os.Exit(1) 34 | } 35 | } 36 | 37 | func generate(cmd *cobra.Command, args []string) { 38 | cfgFilepath, err := cmd.Flags().GetString("config") 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | tygoConfig := config.ReadFromFilepath(cfgFilepath) 43 | t := tygo.New(&tygoConfig) 44 | 45 | err = t.Generate() 46 | if err != nil { 47 | log.Fatalf("Tygo failed: %v", err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | 7 | "github.com/gzuidhof/tygo/tygo" 8 | "gopkg.in/yaml.v2" 9 | ) 10 | 11 | func ReadFromFilepath(cfgFilepath string) tygo.Config { 12 | b, err := ioutil.ReadFile(cfgFilepath) 13 | if err != nil { 14 | log.Fatalf("Could not read config file from %s: %v", cfgFilepath, err) 15 | } 16 | conf := tygo.Config{} 17 | err = yaml.Unmarshal(b, &conf) 18 | if err != nil { 19 | log.Fatalf("Could not parse config file from: %v", err) 20 | } 21 | 22 | return conf 23 | } 24 | -------------------------------------------------------------------------------- /examples/abstract/excluded.go: -------------------------------------------------------------------------------- 1 | package abstract 2 | 3 | const ShouldNotBePresent = "because it's an ignored file" 4 | -------------------------------------------------------------------------------- /examples/abstract/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | export type Something = string | number; 3 | 4 | ////////// 5 | // source: iota.go 6 | 7 | export type MyIotaType = number /* int */; 8 | export const Zero: MyIotaType = 0; 9 | export const One: MyIotaType = 1; 10 | export const Two: MyIotaType = 2; 11 | export const Four: MyIotaType = 4; 12 | export const FourString: string = "four"; 13 | export const AlsoFourString: string = "four"; 14 | export const Five = 5; 15 | export const FiveAgain = 5; 16 | export const Sixteen = 10 + 6; 17 | export const Seventeen = 11 + 6; 18 | 19 | ////////// 20 | // source: misc.go 21 | /* 22 | Package level 23 | Second line of package level comment. 24 | */ 25 | 26 | /** 27 | * Comment belonging to Foo 28 | */ 29 | export type Foo = string; 30 | export type FooInt64 = number /* int64 */; 31 | /** 32 | * Comment for the const group declaration 33 | */ 34 | export const ConstNumberValue = 123; // Line comment behind field with value 123 35 | /** 36 | * Individual comment for field ConstStringValue 37 | */ 38 | export const ConstStringValue = "abc"; 39 | /** 40 | * Comment for the const group declaration 41 | */ 42 | export const ConstFooValue: Foo = "foo_const_value"; 43 | export const Alice = "Alice"; 44 | /** 45 | * Multiline comment for StructBar 46 | * Some more text 47 | */ 48 | export interface StructBar { 49 | /** 50 | * Comment for field Field of type Foo 51 | */ 52 | field: Foo; // Line Comment for field Field of type Foo 53 | weird: number /* int64 */; 54 | field_that_should_be_optional?: string; 55 | field_that_should_not_be_optional: string; 56 | readonly field_that_should_be_readonly: string; 57 | } 58 | -------------------------------------------------------------------------------- /examples/abstract/iota.go: -------------------------------------------------------------------------------- 1 | package abstract 2 | 3 | type MyIotaType int 4 | 5 | const ( 6 | Zero MyIotaType = iota 7 | One 8 | Two 9 | _ 10 | Four 11 | FourString string = "four" 12 | _ 13 | AlsoFourString 14 | Five = 5 15 | FiveAgain 16 | 17 | Sixteen = iota + 6 18 | Seventeen 19 | ) 20 | -------------------------------------------------------------------------------- /examples/abstract/misc.go: -------------------------------------------------------------------------------- 1 | // Package level 2 | // Second line of package level comment. 3 | package abstract 4 | 5 | // DROPPED: Floating comment at the top 6 | 7 | // Comment belonging to Foo 8 | type Foo string 9 | type FooInt64 int64 10 | 11 | // Comment for the const group declaration 12 | const ( 13 | ConstNumberValue = 123 // Line comment behind field with value 123 14 | // Individual comment for field ConstStringValue 15 | ConstStringValue = "abc" 16 | ConstFooValue Foo = "foo_const_value" 17 | ) // DROPPED: Line comment after grouped const 18 | 19 | const Alice = "Alice" 20 | 21 | /* 22 | DROPPED: Floating multiline comment somewhere in the middle 23 | Line two 24 | */ 25 | 26 | /* 27 | Multiline comment for StructBar 28 | Some more text 29 | */ 30 | type StructBar struct { 31 | // Comment for field Field of type Foo 32 | Field Foo `json:"field"` // Line Comment for field Field of type Foo 33 | FieldWithWeirdJSONTag int64 `json:"weird"` 34 | 35 | FieldThatShouldBeOptional *string `json:"field_that_should_be_optional"` 36 | FieldThatShouldNotBeOptional *string `json:"field_that_should_not_be_optional" tstype:",required"` 37 | FieldThatShouldBeReadonly string `json:"field_that_should_be_readonly" tstype:",readonly"` 38 | } 39 | 40 | // DROPPED: Floating comment at the end 41 | -------------------------------------------------------------------------------- /examples/bookstore/author.go: -------------------------------------------------------------------------------- 1 | package bookapp 2 | 3 | type AuthorBookListing struct { 4 | AuthorName string `json:"author_name"` 5 | WrittenBooks []Book `json:"written_books"` 6 | } 7 | 8 | type AuthorWithInheritance[T int] struct { 9 | ID T `json:"id"` 10 | } 11 | -------------------------------------------------------------------------------- /examples/bookstore/book.go: -------------------------------------------------------------------------------- 1 | package bookapp 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/google/uuid" 7 | "gopkg.in/guregu/null.v4" 8 | ) 9 | 10 | type ISBN null.String 11 | 12 | type Chapter struct { 13 | // Chapter title 14 | Title string `json:"title"` 15 | // The amount of words in this chapter 16 | NumberOfWords uint `json:"number_of_words"` 17 | } 18 | 19 | type Book struct { 20 | BookID uuid.UUID `json:"book_id"` // A line comment about BookID that should be kept. 21 | Title string `json:"title"` 22 | // ISBN identifier of the book, null if not known. 23 | ISBN ISBN `json:"isbn"` 24 | 25 | Genre string `json:"genre" tstype:"'novel' | 'crime' | 'fantasy'"` 26 | Chapters []Chapter `json:"chapters"` 27 | 28 | PublishedAt *time.Time `json:"published_at"` 29 | } 30 | 31 | type TextBook[T int] struct { 32 | Book `tstype:",extends"` 33 | Pages T ` json:"pages"` 34 | } 35 | -------------------------------------------------------------------------------- /examples/bookstore/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: author.go 5 | 6 | export interface AuthorBookListing { 7 | author_name: string; 8 | written_books: Book[]; 9 | } 10 | export interface AuthorWithInheritance { 11 | id: T; 12 | } 13 | 14 | ////////// 15 | // source: book.go 16 | 17 | export type ISBN = string | null; 18 | export interface Chapter { 19 | /** 20 | * Chapter title 21 | */ 22 | title: string; 23 | /** 24 | * The amount of words in this chapter 25 | */ 26 | number_of_words: number /* uint */; 27 | } 28 | export interface Book { 29 | book_id: string; // A line comment about BookID that should be kept. 30 | title: string; 31 | /** 32 | * ISBN identifier of the book, null if not known. 33 | */ 34 | isbn: ISBN; 35 | genre: 'novel' | 'crime' | 'fantasy'; 36 | chapters: Chapter[]; 37 | published_at?: string /* RFC 3339 formatted */; 38 | } 39 | export interface TextBook extends Book { 40 | pages: T; 41 | } 42 | -------------------------------------------------------------------------------- /examples/directive/directive.go: -------------------------------------------------------------------------------- 1 | // This example is here to reproduce Github issue #26 2 | // Directive comments should not be output. 3 | // 4 | // See https://github.com/gzuidhof/tygo/issues/26 5 | package directive 6 | 7 | // Comment above a directive 8 | // 9 | //go:foo 10 | //go:bar 11 | const SomeValue = 3 //comment:test 12 | 13 | // Empty Comment 14 | const AnotherValue = 4 // 15 | 16 | //go:something 17 | const DirectiveOnly = 5 18 | 19 | // RepoIndexerType specifies the repository indexer type 20 | type RepoIndexerType int //revive:disable-line:exported 21 | 22 | const ( 23 | // RepoIndexerTypeCode code indexer 24 | RepoIndexerTypeCode RepoIndexerType = iota // 0 25 | // RepoIndexerTypeStats repository stats indexer 26 | RepoIndexerTypeStats // 1 27 | ) 28 | 29 | const A = "a" 30 | const B = "a" 31 | const C = "c" 32 | -------------------------------------------------------------------------------- /examples/directive/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: directive.go 5 | /* 6 | This example is here to reproduce Github issue #26 7 | Directive comments should not be output. 8 | 9 | See https://github.com/gzuidhof/tygo/issues/26 10 | */ 11 | 12 | /** 13 | * Comment above a directive 14 | */ 15 | export const SomeValue = 3; 16 | /** 17 | * Empty Comment 18 | */ 19 | export const AnotherValue = 4; 20 | 21 | export const DirectiveOnly = 5; 22 | /** 23 | * RepoIndexerType specifies the repository indexer type 24 | */ 25 | export type RepoIndexerType = number /* int */; 26 | /** 27 | * RepoIndexerTypeCode code indexer 28 | */ 29 | export const RepoIndexerTypeCode: RepoIndexerType = 0; // 0 30 | /** 31 | * RepoIndexerTypeStats repository stats indexer 32 | */ 33 | export const RepoIndexerTypeStats: RepoIndexerType = 1; // 1 34 | export const A = "a"; 35 | export const B = "a"; 36 | export const C = "c"; 37 | -------------------------------------------------------------------------------- /examples/embed/embed.go: -------------------------------------------------------------------------------- 1 | package embed 2 | 3 | import bookapp "github.com/gzuidhof/tygo/examples/bookstore" 4 | 5 | // TokenType Built-in type alias 6 | type TokenType string 7 | 8 | type StructEmbed struct { 9 | Base `json:",inline" tstype:",extends"` // embed struct with `tstype:"extends"` 10 | TokenType `json:"tokenType"` // built-in type field without `tstype:"extends"` 11 | Reference `json:"reference"` // embed struct without `tstype:"extends"` 12 | OtherReference Reference `json:"other_reference"` 13 | Bar string `json:"bar"` 14 | bookapp.Book `json:"book"` // embed external struct without `tstype:"extends"` 15 | *bookapp.Chapter `json:"chapter"` // embed external struct pointer without `tstype:"extends"` 16 | } 17 | -------------------------------------------------------------------------------- /examples/embed/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | import * as bookapp from "../bookstore" 3 | 4 | ////////// 5 | // source: embed.go 6 | 7 | /** 8 | * TokenType Built-in type alias 9 | */ 10 | export type TokenType = string; 11 | export interface StructEmbed extends Base { 12 | tokenType: TokenType; // built-in type field without `tstype:"extends"` 13 | reference: Reference; // embed struct without `tstype:"extends"` 14 | other_reference: Reference; 15 | bar: string; 16 | book: bookapp.Book; // embed external struct without `tstype:"extends"` 17 | chapter?: bookapp.Chapter; // embed external struct pointer without `tstype:"extends"` 18 | } 19 | 20 | ////////// 21 | // source: types.go 22 | /* 23 | Package embed types defined in the Go file after the parsed file in the same package 24 | */ 25 | 26 | export interface Base { 27 | id: string; 28 | } 29 | /** 30 | * Reference struct type, defined after embed.go, the same pkg but not the same file 31 | */ 32 | export interface Reference { 33 | foo: string; 34 | } 35 | -------------------------------------------------------------------------------- /examples/embed/types.go: -------------------------------------------------------------------------------- 1 | // Package embed types defined in the Go file after the parsed file in the same package 2 | package embed 3 | 4 | type Base struct { 5 | ID string `json:"id"` 6 | } 7 | 8 | // Reference struct type, defined after embed.go, the same pkg but not the same file 9 | type Reference struct { 10 | Foo string `json:"foo"` 11 | } 12 | -------------------------------------------------------------------------------- /examples/emit/custom.go: -------------------------------------------------------------------------------- 1 | package emit 2 | 3 | // emit directive on a string literal emits that value. 4 | // 5 | //tygo:emit 6 | var _ = `export type OtherStructAsTuple=[ 7 | a:number, 8 | b:number, 9 | c:string, 10 | ] 11 | ` 12 | 13 | //tygo:emit This has no effect, only strings. 14 | var _ = 12 15 | 16 | // a non-string var is ignored. A var with no comment is ignored. 17 | 18 | var foo = " " 19 | 20 | // CustomMarshalled illustrates getting tygo to emit literal text 21 | // This solves the problem of a struct field being marshalled into a tuple. 22 | // 23 | // emit directive on a struct emits the remainder of the directive line 24 | // 25 | //tygo:emit export type StructAsTuple=[a:number, b:number, c:string] 26 | type CustomMarshalled struct { 27 | Content []StructAsTuple `json:"content"` 28 | } 29 | 30 | //tygo:emit export type Genre = "novel" | "crime" | "fantasy" 31 | type Book struct { 32 | Title string `json:"title"` 33 | Genre string `json:"genre" tstype:"Genre"` 34 | } 35 | -------------------------------------------------------------------------------- /examples/emit/excluded.go: -------------------------------------------------------------------------------- 1 | package emit 2 | 3 | type StructAsTuple struct { 4 | A int 5 | B float64 6 | C string 7 | } 8 | -------------------------------------------------------------------------------- /examples/emit/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: custom.go 5 | 6 | export type OtherStructAsTuple=[ 7 | a:number, 8 | b:number, 9 | c:string, 10 | ] 11 | 12 | export type StructAsTuple=[a:number, b:number, c:string] 13 | /** 14 | * CustomMarshalled illustrates getting tygo to emit literal text 15 | * This solves the problem of a struct field being marshalled into a tuple. 16 | * emit directive on a struct emits the remainder of the directive line 17 | */ 18 | export interface CustomMarshalled { 19 | content: StructAsTuple[]; 20 | } 21 | export type Genre = "novel" | "crime" | "fantasy" 22 | 23 | export interface Book { 24 | title: string; 25 | genre: Genre; 26 | } 27 | -------------------------------------------------------------------------------- /examples/generic/generic.go: -------------------------------------------------------------------------------- 1 | package generic 2 | 3 | // Comment for UnionType 4 | type UnionType interface { 5 | // Comment for fields are possible 6 | uint64 | string | *bool // comment after 7 | 8 | // Comment for a method 9 | SomeMethod() string 10 | } 11 | 12 | type Derived interface { 13 | ~int | string // Line comment 14 | } 15 | 16 | type Any interface { 17 | string | any 18 | } 19 | 20 | type Empty interface{} 21 | 22 | type Something any 23 | 24 | type EmptyStruct struct{} 25 | 26 | type ValAndPtr[V any, PT *V, Unused ~uint64] struct { 27 | Val V 28 | // Comment for ptr field 29 | Ptr PT // ptr line comment 30 | } 31 | 32 | type ABCD[A, B string, C UnionType, D int64 | bool] struct { 33 | A A `json:"a"` 34 | B B `json:"b"` 35 | C C `json:"c"` 36 | D D `json:"d"` 37 | } 38 | 39 | type Foo[A string | uint64, B *A] struct { 40 | Bar A 41 | Boo B 42 | } 43 | 44 | type WithFooGenericTypeArg[A Foo[string, *string]] struct { 45 | SomeField A `json:"some_field"` 46 | } 47 | 48 | // Should not be output as it's a function 49 | func (f Foo[int, Derived]) DoSomething() { 50 | panic("something") 51 | } 52 | 53 | type Single[S string | uint] struct { 54 | Field S 55 | } 56 | 57 | type SingleSpecific = Single[string] 58 | -------------------------------------------------------------------------------- /examples/generic/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: generic.go 5 | 6 | /** 7 | * Comment for UnionType 8 | */ 9 | export type UnionType = 10 | /** 11 | * Comment for fields are possible 12 | */ 13 | number /* uint64 */ | string | boolean | undefined // comment after 14 | ; 15 | export type Derived = 16 | number /* int */ | string // Line comment 17 | ; 18 | export type Any = 19 | string | unknown; 20 | export type Empty = unknown; 21 | export type Something = any; 22 | export interface EmptyStruct { 23 | } 24 | export interface ValAndPtr { 25 | Val: V; 26 | /** 27 | * Comment for ptr field 28 | */ 29 | Ptr: PT; // ptr line comment 30 | } 31 | export interface ABCD { 32 | a: A; 33 | b: B; 34 | c: C; 35 | d: D; 36 | } 37 | export interface Foo { 38 | Bar: A; 39 | Boo: B; 40 | } 41 | export interface WithFooGenericTypeArg> { 42 | some_field: A; 43 | } 44 | export interface Single { 45 | Field: S; 46 | } 47 | export type SingleSpecific = Single; 48 | -------------------------------------------------------------------------------- /examples/generic_any/any.go: -------------------------------------------------------------------------------- 1 | // Example for https://github.com/gzuidhof/tygo/issues/65 2 | package genericany 3 | 4 | type AnyStructField[T any] struct { 5 | Value T 6 | SomeField string 7 | } 8 | 9 | type JsonArray[T any] []T 10 | -------------------------------------------------------------------------------- /examples/generic_any/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: any.go 5 | /* 6 | Example for https://github.com/gzuidhof/tygo/issues/65 7 | */ 8 | 9 | export interface AnyStructField { 10 | Value: T; 11 | SomeField: string; 12 | } 13 | export type JsonArray = T[]; 14 | -------------------------------------------------------------------------------- /examples/globalconfig/globalconfig.go: -------------------------------------------------------------------------------- 1 | package globalconfig 2 | 3 | import "time" 4 | 5 | type Config struct { 6 | Duration time.Duration 7 | } 8 | -------------------------------------------------------------------------------- /examples/inheritance/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | import * as bookapp from "../bookstore" 3 | 4 | ////////// 5 | // source: inheritance.go 6 | 7 | export interface Base { 8 | name: string; 9 | } 10 | export interface Base2 { 11 | id: T; 12 | } 13 | export interface Base3 { 14 | class: T; 15 | level: X; 16 | } 17 | export interface Other extends Base, Base2, Partial>, bookapp.Book, bookapp.TextBook { 18 | otherWithBase: Base; 19 | otherWithBase2: Base2; 20 | otherValue: string; 21 | author: bookapp.AuthorWithInheritance; 22 | } 23 | -------------------------------------------------------------------------------- /examples/inheritance/inheritance.go: -------------------------------------------------------------------------------- 1 | package inheritance 2 | 3 | import ( 4 | bookapp "github.com/gzuidhof/tygo/examples/bookstore" 5 | ) 6 | 7 | type Base struct { 8 | Name string `json:"name"` 9 | } 10 | 11 | type Base2[T string | int] struct { 12 | ID T `json:"id"` 13 | } 14 | 15 | type Base3[T string, X int] struct { 16 | Class T `json:"class"` 17 | Level X `json:"level"` 18 | } 19 | 20 | type Other[T int, X string] struct { 21 | *Base `tstype:",extends,required"` 22 | Base2[T] `tstype:",extends"` 23 | *Base3[X, T] `tstype:",extends"` 24 | OtherWithBase Base ` json:"otherWithBase"` 25 | OtherWithBase2 Base2[X] ` json:"otherWithBase2"` 26 | OtherValue string ` json:"otherValue"` 27 | Author bookapp.AuthorWithInheritance[T] `tstype:"bookapp.AuthorWithInheritance" json:"author"` 28 | bookapp.Book `tstype:",extends"` 29 | TextBook *bookapp.TextBook[T] `tstype:",extends,required"` 30 | } 31 | -------------------------------------------------------------------------------- /examples/interface/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: interface.go 5 | 6 | /** 7 | * Plain interfaces should output the unknown type, which is `any` by default but can also be configured as `unknown`). 8 | */ 9 | export type InterfaceOnly = any; 10 | -------------------------------------------------------------------------------- /examples/interface/interface.go: -------------------------------------------------------------------------------- 1 | package interfaceoutput 2 | 3 | // Plain interfaces should output the unknown type, which is `any` by default but can also be configured as `unknown`). 4 | type InterfaceOnly interface { 5 | InterfaceMethod() string 6 | } 7 | -------------------------------------------------------------------------------- /examples/noComments/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: noComments.go 5 | 6 | export type UserRole = string; 7 | export const UserRoleDefault: UserRole = "viewer"; 8 | export const UserRoleEditor: UserRole = "editor"; 9 | export interface User { 10 | id: string | null; 11 | } 12 | -------------------------------------------------------------------------------- /examples/noComments/noComments.go: -------------------------------------------------------------------------------- 1 | // noComments is a package-level comment. By default, it is preserved. 2 | // with preserveComments configured to "none", it won't be preserved. 3 | package noComments 4 | 5 | import "github.com/google/uuid" 6 | 7 | // This is a block comment in the package body. By default, it is preserved. 8 | // With preserveComments configured to "none", it won't be preserved. 9 | 10 | // Type comments are preserved by default or with "types". It won't be preserved with "none" 11 | type UserRole = string 12 | 13 | const ( 14 | // Const comments are preserved by default or with "types". It won't be preserved with "none" 15 | UserRoleDefault UserRole = "viewer" 16 | UserRoleEditor UserRole = "editor" // Line comments are preserved by default. With preserveComments configured to "none", it won't be preserved. 17 | ) 18 | 19 | type User struct { 20 | // Struct field comments are preserved by default or with "types". It won't be preserved with "none" 21 | ID uuid.NullUUID `json:"id" tstype:"string | null"` 22 | } 23 | -------------------------------------------------------------------------------- /examples/preserveTypeComments/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: preserveTypeComments.go 5 | 6 | /** 7 | * Type comments are preserved, unless configured to "none" 8 | */ 9 | export type UserRole = string; 10 | /** 11 | * Const comments are preserved, unless configured to "none" 12 | */ 13 | export const UserRoleDefault: UserRole = "viewer"; 14 | export const UserRoleEditor: UserRole = "editor"; 15 | export interface User { 16 | /** 17 | * Struct field comments are preserved unless configured to "none" 18 | */ 19 | id: string | null; 20 | } 21 | -------------------------------------------------------------------------------- /examples/preserveTypeComments/preserveTypeComments.go: -------------------------------------------------------------------------------- 1 | // preservetypecomments is a package-level comment. By default, it is preserved. 2 | // with preserveComments configured to "types", it won't be preserved. 3 | package preservetypecomments 4 | 5 | import "github.com/google/uuid" 6 | 7 | // This is a block comment in the package body. By default, it is preserved. 8 | // With preserveComments configured to "types", it won't be preserved. 9 | 10 | // Type comments are preserved, unless configured to "none" 11 | type UserRole = string 12 | 13 | const ( 14 | // Const comments are preserved, unless configured to "none" 15 | UserRoleDefault UserRole = "viewer" 16 | UserRoleEditor UserRole = "editor" // Line comments are preserved by default. With preserveComments configured to "types", it won't be preserved. 17 | ) 18 | 19 | type User struct { 20 | // Struct field comments are preserved unless configured to "none" 21 | ID uuid.NullUUID `json:"id" tstype:"string | null"` 22 | } 23 | -------------------------------------------------------------------------------- /examples/rune/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: rune.go 5 | 6 | /** 7 | * Should be a number in TypeScript. 8 | */ 9 | export type MyRune = number /* rune */; 10 | -------------------------------------------------------------------------------- /examples/rune/rune.go: -------------------------------------------------------------------------------- 1 | package rune 2 | 3 | // Should be a number in TypeScript. 4 | type MyRune rune 5 | -------------------------------------------------------------------------------- /examples/simple/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: simple.go 5 | 6 | /** 7 | * Comments are kept :) 8 | */ 9 | export type ComplexType = { [key: string]: { [key: number /* uint16 */]: number /* uint32 */ | undefined}}; 10 | export type UserRole = string; 11 | export const UserRoleDefault: UserRole = "viewer"; 12 | export const UserRoleEditor: UserRole = "editor"; // Line comments are also kept 13 | export interface UserEntry { 14 | /** 15 | * Instead of specifying `tstype` we could also declare the typing 16 | * for uuid.NullUUID in the config file. 17 | */ 18 | id: string | null; 19 | prefs: { [key: string]: { 20 | foo: number /* uint32 */; 21 | /** 22 | * An unknown type without a `tstype` tag or mapping in the config file 23 | * uses the `fallback_type`, which defaults to `any`. 24 | */ 25 | bar: unknown /* uuid.UUID */; 26 | }}; 27 | address?: string; 28 | nickname?: string; 29 | role: UserRole; 30 | created_at?: string /* RFC3339 */; 31 | complex: ComplexType; 32 | } 33 | export interface ListUsersResponse { 34 | users: UserEntry[]; 35 | } 36 | -------------------------------------------------------------------------------- /examples/simple/simple.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/google/uuid" 7 | ) 8 | 9 | // Comments are kept :) 10 | type ComplexType map[string]map[uint16]*uint32 11 | 12 | type UserRole = string 13 | 14 | const ( 15 | UserRoleDefault UserRole = "viewer" 16 | UserRoleEditor UserRole = "editor" // Line comments are also kept 17 | ) 18 | 19 | type UserEntry struct { 20 | // Instead of specifying `tstype` we could also declare the typing 21 | // for uuid.NullUUID in the config file. 22 | ID uuid.NullUUID `json:"id" tstype:"string | null"` 23 | 24 | Preferences map[string]struct { 25 | Foo uint32 `json:"foo"` 26 | // An unknown type without a `tstype` tag or mapping in the config file 27 | // uses the `fallback_type`, which defaults to `any`. 28 | Bar uuid.UUID `json:"bar"` 29 | } `json:"prefs"` 30 | 31 | MaybeFieldWithStar *string `json:"address"` 32 | Nickname string `json:"nickname,omitempty"` 33 | Role UserRole `json:"role"` 34 | CreatedAt time.Time `json:"created_at,omitzero"` 35 | 36 | Complex ComplexType `json:"complex"` 37 | unexported bool // Unexported fields won't be in the output 38 | } 39 | 40 | type ListUsersResponse struct { 41 | Users []UserEntry `json:"users"` 42 | } 43 | -------------------------------------------------------------------------------- /examples/yaml/index.ts: -------------------------------------------------------------------------------- 1 | // Code generated by tygo. DO NOT EDIT. 2 | 3 | ////////// 4 | // source: yaml.go 5 | 6 | export interface YAMLTest { 7 | id: string; 8 | prefs: { [key: string]: { 9 | foo: number /* uint32 */; 10 | }}; 11 | address?: string; 12 | nickname?: string; 13 | thiswillgetlowercased: string; 14 | } 15 | -------------------------------------------------------------------------------- /examples/yaml/yaml.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | type YAMLTest struct { 4 | ID string `yaml:"id"` 5 | 6 | Preferences map[string]struct { 7 | Foo uint32 `yaml:"foo"` 8 | } `yaml:"prefs"` 9 | 10 | MaybeFieldWithStar *string `yaml:"address"` 11 | Nickname string `yaml:"nickname,omitempty"` 12 | 13 | ThisWillGetLowercased string 14 | 15 | unexported bool // Unexported fields won't be in the output 16 | } 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gzuidhof/tygo 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/spf13/cobra v1.3.0 7 | gopkg.in/yaml.v2 v2.4.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | golang.org/x/mod v0.5.1 // indirect 14 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect 15 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 16 | gopkg.in/yaml.v3 v3.0.1 // indirect 17 | ) 18 | 19 | require ( 20 | github.com/fatih/structtag v1.2.0 21 | github.com/google/uuid v1.3.0 22 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 23 | github.com/spf13/pflag v1.0.5 // indirect 24 | github.com/stretchr/testify v1.9.0 25 | golang.org/x/tools v0.1.9 26 | gopkg.in/guregu/null.v4 v4.0.0 27 | ) 28 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= 22 | cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= 23 | cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= 24 | cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= 25 | cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= 26 | cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= 27 | cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= 28 | cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= 29 | cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= 30 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 31 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 32 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 33 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 34 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 35 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 36 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 37 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 38 | cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= 39 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 40 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 41 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 42 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 43 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 44 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 45 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 46 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 47 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 48 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 49 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 50 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 51 | github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= 52 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 53 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 54 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 55 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 56 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 57 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 58 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 59 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 60 | github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= 61 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 62 | github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 63 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 64 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 65 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 66 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 67 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 68 | github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 69 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 70 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 71 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 72 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 73 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 74 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 75 | github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= 76 | github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= 77 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 78 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 79 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 80 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 81 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 82 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 83 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 84 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 85 | github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 86 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 87 | github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 88 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 89 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 90 | github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 91 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 92 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 93 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 94 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 95 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 96 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 97 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 98 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 99 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 100 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= 101 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 102 | github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= 103 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 104 | github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= 105 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 106 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 107 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 108 | github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= 109 | github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 110 | github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= 111 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 112 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 113 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 114 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 115 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 116 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 117 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 118 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 119 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 120 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 121 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 122 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 123 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 124 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 125 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 126 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 127 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 128 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 129 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 130 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 131 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 132 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 133 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 134 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 135 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 136 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 137 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 138 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 139 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 140 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 141 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 142 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 143 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 144 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 145 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 146 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 147 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 148 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 149 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 150 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 151 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 152 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 153 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 154 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 155 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 156 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 157 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 158 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 159 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 160 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 161 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 162 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 163 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 164 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 165 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 166 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 167 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 168 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 169 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 170 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 171 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 172 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 173 | github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 174 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 175 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 176 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 177 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 178 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 179 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 180 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 181 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 182 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 183 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 184 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 185 | github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 186 | github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 187 | github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 188 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 189 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 190 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 191 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 192 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 193 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 194 | github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= 195 | github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 196 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 197 | github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= 198 | github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= 199 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 200 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 201 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 202 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 203 | github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 204 | github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 205 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 206 | github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 207 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 208 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 209 | github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 210 | github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= 211 | github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 212 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 213 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 214 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 215 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 216 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 217 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 218 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 219 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 220 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 221 | github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= 222 | github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= 223 | github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= 224 | github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= 225 | github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= 226 | github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= 227 | github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 228 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 229 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 230 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 231 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 232 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 233 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 234 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 235 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 236 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 237 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 238 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 239 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 240 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 241 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 242 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 243 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 244 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 245 | github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= 246 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 247 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 248 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 249 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 250 | github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= 251 | github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 252 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 253 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 254 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 255 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 256 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 257 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 258 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 259 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 260 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 261 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 262 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 263 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 264 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 265 | github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= 266 | github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= 267 | github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 268 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 269 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 270 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 271 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 272 | github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 273 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 274 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 275 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 276 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 277 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 278 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 279 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 280 | github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 281 | github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 282 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 283 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 284 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 285 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 286 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 287 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 288 | github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 289 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 290 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 291 | github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 292 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 293 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 294 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 295 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 296 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 297 | github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 298 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 299 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 300 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 301 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 302 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 303 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 304 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 305 | github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= 306 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 307 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 308 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 309 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 310 | github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= 311 | github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 312 | github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 313 | github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= 314 | github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= 315 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 316 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 317 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 318 | github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= 319 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 320 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 321 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 322 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 323 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 324 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 325 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 326 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 327 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 328 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 329 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 330 | github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 331 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 332 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 333 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 334 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 335 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 336 | go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= 337 | go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= 338 | go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= 339 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 340 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 341 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 342 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 343 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 344 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 345 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 346 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 347 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 348 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 349 | go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= 350 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 351 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 352 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 353 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 354 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 355 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 356 | golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 357 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 358 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 359 | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 360 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 361 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 362 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 363 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 364 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 365 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 366 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 367 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 368 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 369 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 370 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 371 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 372 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 373 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 374 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 375 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 376 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 377 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 378 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 379 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 380 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 381 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 382 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 383 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 384 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 385 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 386 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 387 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 388 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 389 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 390 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 391 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 392 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 393 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 394 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 395 | golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 396 | golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= 397 | golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 398 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 399 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 400 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 401 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 402 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 403 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 404 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 405 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 406 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 407 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 408 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 409 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 410 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 411 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 412 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 413 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 414 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 415 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 416 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 417 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 418 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 419 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 420 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 421 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 422 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 423 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 424 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 425 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 426 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 427 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 428 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 429 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 430 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 431 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 432 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 433 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 434 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 435 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 436 | golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= 437 | golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 438 | golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 439 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 440 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 441 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 442 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 443 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 444 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 445 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 446 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 447 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 448 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 449 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 450 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 451 | golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 452 | golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 453 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 454 | golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 455 | golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 456 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 457 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 458 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 459 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 460 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 461 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 462 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 463 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 464 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 465 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 466 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 467 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 468 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 469 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 470 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 471 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 472 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 473 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 474 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 475 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 476 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 477 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 478 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 479 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 480 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 481 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 482 | golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 483 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 484 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 485 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 486 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 487 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 488 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 489 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 490 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 491 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 492 | golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 493 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 494 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 495 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 496 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 497 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 498 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 499 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 500 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 501 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 502 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 503 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 504 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 505 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 506 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 507 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 508 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 509 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 510 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 511 | golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 512 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 513 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 514 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 515 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 516 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 517 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 518 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 519 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 520 | golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 521 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 522 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 523 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 524 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 525 | golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 526 | golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 527 | golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 528 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 529 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 530 | golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 531 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= 532 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 533 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 534 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 535 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 536 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 537 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 538 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 539 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 540 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 541 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 542 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 543 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 544 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 545 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 546 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 547 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 548 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 549 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 550 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 551 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 552 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 553 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 554 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 555 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 556 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 557 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 558 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 559 | golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 560 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 561 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 562 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 563 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 564 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 565 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 566 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 567 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 568 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 569 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 570 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 571 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 572 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 573 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 574 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 575 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 576 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 577 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 578 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 579 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 580 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 581 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 582 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 583 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 584 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 585 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 586 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 587 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 588 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 589 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 590 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 591 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 592 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 593 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 594 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 595 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 596 | golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 597 | golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 598 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 599 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 600 | golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= 601 | golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= 602 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 603 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 604 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 605 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 606 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 607 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 608 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 609 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 610 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 611 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 612 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 613 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 614 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 615 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 616 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 617 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 618 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 619 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 620 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 621 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 622 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 623 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 624 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 625 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 626 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 627 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 628 | google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= 629 | google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= 630 | google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= 631 | google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= 632 | google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= 633 | google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 634 | google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 635 | google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= 636 | google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= 637 | google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= 638 | google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= 639 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 640 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 641 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 642 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 643 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 644 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 645 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 646 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 647 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 648 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 649 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 650 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 651 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 652 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 653 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 654 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 655 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 656 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 657 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 658 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 659 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 660 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 661 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 662 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 663 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 664 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 665 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 666 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 667 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 668 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 669 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 670 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 671 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 672 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 673 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 674 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 675 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 676 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 677 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 678 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 679 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 680 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 681 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 682 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 683 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 684 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 685 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 686 | google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= 687 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 688 | google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 689 | google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 690 | google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= 691 | google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 692 | google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 693 | google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 694 | google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 695 | google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= 696 | google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 697 | google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 698 | google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 699 | google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 700 | google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 701 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 702 | google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 703 | google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 704 | google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 705 | google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 706 | google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 707 | google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 708 | google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 709 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 710 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 711 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 712 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 713 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 714 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 715 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 716 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 717 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 718 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 719 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 720 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 721 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 722 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 723 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 724 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 725 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 726 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 727 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 728 | google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 729 | google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 730 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 731 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 732 | google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 733 | google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 734 | google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 735 | google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= 736 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 737 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 738 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 739 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 740 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 741 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 742 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 743 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 744 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 745 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 746 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 747 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 748 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 749 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 750 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 751 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 752 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 753 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 754 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 755 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 756 | gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= 757 | gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= 758 | gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 759 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 760 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 761 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 762 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 763 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 764 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 765 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 766 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 767 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 768 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 769 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 770 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 771 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 772 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 773 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 774 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 775 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 776 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 777 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 778 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 779 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 780 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 781 | -------------------------------------------------------------------------------- /goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | project_name: tygo 3 | builds: 4 | - binary: tygo 5 | goos: 6 | - windows 7 | - darwin 8 | - linux 9 | goarch: 10 | - amd64 11 | - arm64 12 | ldflags: 13 | - -s -w -X github.com/gzuidhof/tygo/cmd.version={{.Version}} -X github.com/gzuidhof/tygo/cmd.commit={{.Commit}} -X github.com/gzuidhof/tygo/cmd.commitDate={{.CommitDate}} 14 | archives: 15 | - id: tygo 16 | name_template: >- 17 | {{ .ProjectName }}_ 18 | {{- .Tag }}_ 19 | {{- .Os }}_ 20 | {{- .Arch}} 21 | format_overrides: 22 | - goos: windows 23 | format: zip 24 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gzuidhof/tygo/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /tygo.yaml: -------------------------------------------------------------------------------- 1 | # This is a config file that typescriptifies the packages under the example folder. 2 | # and some other packages. 3 | type_mappings: 4 | time.Duration: "number /* int, ns */" 5 | 6 | packages: 7 | - path: "github.com/gzuidhof/tygo/examples/bookstore" 8 | type_mappings: 9 | time.Time: "string /* RFC 3339 formatted */" 10 | null.String: "string | null" 11 | uuid.UUID: "string" 12 | - path: "github.com/gzuidhof/tygo/examples/abstract" 13 | indent: " " 14 | exclude_files: 15 | - "excluded.go" 16 | frontmatter: 17 | | # We can define some additional text to put at the start of the file. 18 | export type Something = string | number; 19 | - path: "github.com/gzuidhof/tygo/examples/simple" 20 | fallback_type: unknown 21 | - path: "github.com/gzuidhof/tygo/examples/inheritance" 22 | fallback_type: unknown 23 | frontmatter: 24 | | # We can define some additional text to put at the start of the file. 25 | import * as bookapp from "../bookstore" 26 | - path: "github.com/gzuidhof/tygo/examples/embed" 27 | fallback_type: unknown 28 | type_mappings: 29 | bookapp.Book: "bookapp.Book" 30 | bookapp.Chapter: "bookapp.Chapter" 31 | frontmatter: 32 | | # We can define some additional text to put at the start of the file. 33 | import * as bookapp from "../bookstore" 34 | - path: "github.com/gzuidhof/tygo/examples/generic" 35 | fallback_type: unknown 36 | - path: "github.com/gzuidhof/tygo/examples/generic_any" 37 | - path: "github.com/gzuidhof/tygo/examples/preserveTypeComments" 38 | fallback_type: unknown 39 | preserve_comments: "types" 40 | - path: "github.com/gzuidhof/tygo/examples/noComments" 41 | fallback_type: unknown 42 | preserve_comments: "none" 43 | # Generate the "net/http" output example, note the output is in gitignore as it's pretty big 44 | - path: "net/http" 45 | output_path: "./examples/http/index.ts" 46 | type_mappings: 47 | time.Duration: "number /* time in nanoseconds (time.Duration) */" 48 | # Generate the "time" output example, note the output is in gitignore as it's pretty big 49 | - path: "time" 50 | output_path: "./examples/time/index.ts" 51 | - path: "github.com/gzuidhof/tygo/examples/yaml" 52 | output_path: "./examples/yaml/index.ts" 53 | flavor: "yaml" 54 | - path: "github.com/gzuidhof/tygo/examples/interface" 55 | - path: "github.com/gzuidhof/tygo/examples/directive" 56 | - path: "github.com/gzuidhof/tygo/examples/emit" 57 | exclude_files: 58 | - "excluded.go" 59 | - path: "github.com/gzuidhof/tygo/examples/rune" 60 | 61 | - path: "github.com/gzuidhof/tygo/examples/globalconfig" 62 | 63 | 64 | -------------------------------------------------------------------------------- /tygo/config.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "path/filepath" 7 | "strings" 8 | ) 9 | 10 | const defaultOutputFilename = "index.ts" 11 | const defaultFallbackType = "any" 12 | const defaultPreserveComments = "default" 13 | 14 | type PackageConfig struct { 15 | // The package path just like you would import it in Go 16 | Path string `yaml:"path"` 17 | 18 | // Where this output should be written to. 19 | // If you specify a folder it will be written to a file `index.ts` within that folder. By default it is written into the Golang package folder. 20 | OutputPath string `yaml:"output_path"` 21 | 22 | // Customize the indentation (use \t if you want tabs) 23 | Indent string `yaml:"indent"` 24 | 25 | // Specify your own custom type translations, useful for custom types, `time.Time` and `null.String`. 26 | // Be default unrecognized types will be output as `any /* name */`. 27 | TypeMappings map[string]string `yaml:"type_mappings"` 28 | 29 | // This content will be put at the top of the output Typescript file. 30 | // You would generally use this to import custom types. 31 | Frontmatter string `yaml:"frontmatter"` 32 | 33 | // Filenames of Go source files that should not be included in the Typescript output. 34 | ExcludeFiles []string `yaml:"exclude_files"` 35 | 36 | // Filenames of Go source files that should be included in the Typescript output. 37 | IncludeFiles []string `yaml:"include_files"` 38 | 39 | // FallbackType defines the Typescript type used as a fallback for unknown Go types. 40 | FallbackType string `yaml:"fallback_type"` 41 | 42 | // Flavor defines what the key names of the output types will look like. 43 | // Supported values: "default", "" (same as "default"), "yaml". 44 | // In "default" mode, `json` and `yaml` tags are respected, but otherwise keys are unchanged. 45 | // In "yaml" mode, keys are lowercased to emulate gopkg.in/yaml.v2. 46 | Flavor string `yaml:"flavor"` 47 | 48 | // PreserveComments is an option to preserve comments in the generated TypeScript output. 49 | // Supported values: "default", "" (same as "default"), "types", "none". 50 | // By "default", package-level comments as well as type comments are 51 | // preserved. 52 | // In "types" mode, only type comments are preserved. 53 | // If "none" is supplied, no comments are preserved. 54 | PreserveComments string `yaml:"preserve_comments"` 55 | 56 | // Default interface for Typescript-generated interfaces to extend. 57 | Extends string `yaml:"extends"` 58 | 59 | // Set the optional type (null or undefined). 60 | // Supported values: "default", "undefined" (same as "default"), "" (same as "default"), "null". 61 | // Default is "undefined". 62 | // Useful for usage with JSON marshalers that output null for optional fields (e.g. gofiber JSON). 63 | OptionalType string `yaml:"optional_type"` 64 | } 65 | 66 | type Config struct { 67 | TypeMappings map[string]string `yaml:"type_mappings"` 68 | Packages []*PackageConfig `yaml:"packages"` 69 | } 70 | 71 | func (c Config) PackageNames() []string { 72 | names := make([]string, len(c.Packages)) 73 | 74 | for i, p := range c.Packages { 75 | names[i] = p.Path 76 | } 77 | return names 78 | } 79 | 80 | func (c Config) PackageConfig(packagePath string) *PackageConfig { 81 | for _, pc := range c.Packages { 82 | if pc.Path == packagePath { 83 | pc.TypeMappings = c.mergeMappings(pc.TypeMappings) 84 | pcNormalized, err := pc.Normalize() 85 | if err != nil { 86 | log.Fatalf("Error in config for package %s: %s", packagePath, err) 87 | } 88 | 89 | return &pcNormalized 90 | } 91 | } 92 | log.Fatalf("Config not found for package %s", packagePath) 93 | return nil 94 | } 95 | 96 | func normalizeFlavor(flavor string) (string, error) { 97 | switch flavor { 98 | case "", "default": 99 | return "default", nil 100 | case "yaml": 101 | return "yaml", nil 102 | default: 103 | return "", fmt.Errorf("unsupported flavor: %s", flavor) 104 | } 105 | } 106 | 107 | func normalizePreserveComments(preserveComments string) (string, error) { 108 | switch preserveComments { 109 | case "", "default": 110 | return "default", nil 111 | case "types": 112 | return "types", nil 113 | case "none": 114 | return "none", nil 115 | default: 116 | return "", fmt.Errorf("unsupported preserve_comments: %s", preserveComments) 117 | } 118 | } 119 | 120 | func normalizeOptionalType(optional string) (string, error) { 121 | switch optional { 122 | case "", "default", "undefined": 123 | return "undefined", nil 124 | case "null": 125 | return "null", nil 126 | default: 127 | return "", fmt.Errorf("unsupported optional: %s", optional) 128 | } 129 | } 130 | 131 | func (c PackageConfig) IsFileIgnored(pathToFile string) bool { 132 | basename := filepath.Base(pathToFile) 133 | for _, ef := range c.ExcludeFiles { 134 | if basename == ef { 135 | return true 136 | } 137 | } 138 | 139 | // if defined, only included files are allowed 140 | if len(c.IncludeFiles) > 0 { 141 | for _, include := range c.IncludeFiles { 142 | if basename == include { 143 | return false 144 | } 145 | } 146 | return true 147 | } 148 | 149 | return false 150 | } 151 | 152 | func (c PackageConfig) ResolvedOutputPath(packageDir string) string { 153 | if c.OutputPath == "" { 154 | return filepath.Join(packageDir, defaultOutputFilename) 155 | } else if !strings.HasSuffix(c.OutputPath, ".ts") { 156 | return filepath.Join(c.OutputPath, defaultOutputFilename) 157 | } 158 | return c.OutputPath 159 | } 160 | 161 | // Normalize returns a new PackageConfig with default values set. 162 | func (pc PackageConfig) Normalize() (PackageConfig, error) { 163 | if pc.Indent == "" { 164 | pc.Indent = " " 165 | } 166 | 167 | if pc.FallbackType == "" { 168 | pc.FallbackType = defaultFallbackType 169 | } 170 | 171 | if pc.PreserveComments == "" { 172 | pc.PreserveComments = defaultPreserveComments 173 | } 174 | 175 | var err error 176 | pc.Flavor, err = normalizeFlavor(pc.Flavor) 177 | if err != nil { 178 | return pc, fmt.Errorf("invalid flavor config for package %s: %s", pc.Path, err) 179 | } 180 | 181 | pc.PreserveComments, err = normalizePreserveComments(pc.PreserveComments) 182 | if err != nil { 183 | return pc, fmt.Errorf("invalid preserve_comments config for package %s: %s", pc.Path, err) 184 | } 185 | 186 | pc.OptionalType, err = normalizeOptionalType(pc.OptionalType) 187 | if err != nil { 188 | return pc, fmt.Errorf("invalid optional_type config for package %s: %s", pc.Path, err) 189 | } 190 | 191 | return pc, nil 192 | } 193 | 194 | func (c Config) mergeMappings(pkg map[string]string) map[string]string { 195 | mappings := make(map[string]string) 196 | for k, v := range c.TypeMappings { 197 | mappings[k] = v 198 | } 199 | for k, v := range pkg { 200 | mappings[k] = v 201 | } 202 | return mappings 203 | } 204 | -------------------------------------------------------------------------------- /tygo/convert_string.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "fmt" 5 | "go/parser" 6 | "go/token" 7 | "strings" 8 | ) 9 | 10 | // ConvertGoToTypescript converts Go code string to Typescript. 11 | // 12 | // This is mostly useful for testing purposes inside tygo itself. 13 | func ConvertGoToTypescript(goCode string, pkgConfig PackageConfig) (string, error) { 14 | src := fmt.Sprintf(`package tygoconvert 15 | 16 | %s`, goCode) 17 | 18 | fset := token.NewFileSet() 19 | 20 | f, err := parser.ParseFile(fset, "", src, parser.AllErrors|parser.ParseComments) 21 | if err != nil { 22 | return "", fmt.Errorf("failed to parse source: %w", err) 23 | } 24 | 25 | pkgConfig, err = pkgConfig.Normalize() 26 | if err != nil { 27 | return "", fmt.Errorf("failed to normalize package config: %w", err) 28 | } 29 | 30 | pkgGen := &PackageGenerator{ 31 | conf: &pkgConfig, 32 | pkg: nil, 33 | } 34 | 35 | s := new(strings.Builder) 36 | 37 | pkgGen.generateFile(s, f, "") 38 | code := s.String() 39 | 40 | return code, nil 41 | } 42 | -------------------------------------------------------------------------------- /tygo/fixtures_test.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "embed" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | "gopkg.in/yaml.v3" 12 | ) 13 | 14 | // Embed markdown test fixtures 15 | // 16 | //go:embed testdata/fixtures/*.md 17 | var mdfs embed.FS 18 | 19 | type MarkdownFixture struct { 20 | PackageConfig PackageConfig 21 | GoCode string 22 | TsCode string 23 | } 24 | 25 | func TestConvertGoToTypescriptSmoketest(t *testing.T) { 26 | t.Parallel() 27 | 28 | goCode := "type MyType uint8" 29 | tsCode, err := ConvertGoToTypescript(goCode, PackageConfig{}) 30 | require.NoError(t, err) 31 | 32 | expected := `export type MyType = number /* uint8 */; 33 | ` 34 | assert.Equal(t, expected, tsCode) 35 | } 36 | 37 | func parseMarkdownFixtures(fileContents []byte) ([]MarkdownFixture, error) { 38 | fixtures := make([]MarkdownFixture, 0) 39 | currentFixture := MarkdownFixture{} 40 | 41 | currentBlockContents := "" 42 | currentBlockLanguage := "" 43 | inCodeBlock := false 44 | for _, line := range strings.Split(string(fileContents), "\n") { 45 | if strings.HasPrefix(line, "```") { 46 | if inCodeBlock { 47 | // End of code block 48 | if currentBlockLanguage == "ts" || currentBlockLanguage == "typescript" { 49 | // Every fixture ends with a typescript block 50 | currentFixture.TsCode = currentBlockContents 51 | fixtures = append(fixtures, currentFixture) 52 | currentFixture = MarkdownFixture{} 53 | } else if currentBlockLanguage == "go" { 54 | currentFixture.GoCode = currentBlockContents 55 | } else if currentBlockLanguage == "yml" || currentBlockLanguage == "yaml" { 56 | // Parse package config 57 | pc := PackageConfig{} 58 | err := yaml.Unmarshal([]byte(currentBlockContents), &pc) 59 | if err != nil { 60 | return nil, fmt.Errorf("failed to unmarshal package config: %w", err) 61 | } 62 | currentFixture.PackageConfig = pc 63 | } 64 | currentBlockContents = "" 65 | currentBlockLanguage = "" 66 | } else { // Start of code block 67 | language := strings.TrimPrefix(line, "```") 68 | language = strings.TrimSpace(language) 69 | currentBlockLanguage = language 70 | } 71 | inCodeBlock = !inCodeBlock 72 | continue 73 | } 74 | 75 | if inCodeBlock { 76 | currentBlockContents += line + "\n" 77 | } 78 | } 79 | 80 | return fixtures, nil 81 | 82 | } 83 | 84 | // Tests all markdown files in `testdata/fixtures/` directory. 85 | func TestMarkdownFixtures(t *testing.T) { 86 | t.Parallel() 87 | 88 | fixtures, err := mdfs.ReadDir("testdata/fixtures") 89 | require.NoError(t, err) 90 | 91 | for _, fixture := range fixtures { 92 | fixture := fixture 93 | 94 | // Read markdown file 95 | md, err := mdfs.ReadFile("testdata/fixtures/" + fixture.Name()) 96 | require.NoError(t, err) 97 | 98 | testCases, err := parseMarkdownFixtures(md) 99 | require.NoError(t, err) 100 | 101 | for _, tc := range testCases { 102 | tc := tc 103 | t.Run(fixture.Name(), func(t *testing.T) { 104 | t.Parallel() 105 | 106 | tsCode, err := ConvertGoToTypescript(tc.GoCode, tc.PackageConfig) 107 | require.NoError(t, err) 108 | 109 | assert.Equal(t, tc.TsCode, tsCode) 110 | }) 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tygo/generator.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "golang.org/x/tools/go/packages" 9 | ) 10 | 11 | // Generator for one or more input packages, responsible for linking 12 | // them together if necessary. 13 | type Tygo struct { 14 | conf *Config 15 | 16 | packageGenerators map[string]*PackageGenerator 17 | } 18 | 19 | // Responsible for generating the code for an input package 20 | type PackageGenerator struct { 21 | conf *PackageConfig 22 | pkg *packages.Package 23 | GoFiles []string 24 | } 25 | 26 | func New(config *Config) *Tygo { 27 | return &Tygo{ 28 | conf: config, 29 | packageGenerators: make(map[string]*PackageGenerator), 30 | } 31 | } 32 | 33 | func (g *Tygo) SetTypeMapping(goType string, tsType string) { 34 | for _, p := range g.conf.Packages { 35 | p.TypeMappings[goType] = tsType 36 | } 37 | } 38 | 39 | func (g *Tygo) Generate() error { 40 | pkgs, err := packages.Load(&packages.Config{ 41 | Mode: packages.NeedSyntax | packages.NeedFiles, 42 | }, g.conf.PackageNames()...) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | for i, pkg := range pkgs { 48 | if len(pkg.Errors) > 0 { 49 | return fmt.Errorf("%+v", pkg.Errors) 50 | } 51 | 52 | if len(pkg.GoFiles) == 0 { 53 | return fmt.Errorf("no input go files for package index %d", i) 54 | } 55 | 56 | pkgConfig := g.conf.PackageConfig(pkg.ID) 57 | 58 | pkgGen := &PackageGenerator{ 59 | conf: pkgConfig, 60 | GoFiles: pkg.GoFiles, 61 | pkg: pkg, 62 | } 63 | g.packageGenerators[pkg.PkgPath] = pkgGen 64 | code, err := pkgGen.Generate() 65 | if err != nil { 66 | return err 67 | } 68 | 69 | outPath := pkgGen.conf.ResolvedOutputPath(filepath.Dir(pkg.GoFiles[0])) 70 | err = os.MkdirAll(filepath.Dir(outPath), os.ModePerm) 71 | if err != nil { 72 | return nil 73 | } 74 | 75 | err = os.WriteFile(outPath, []byte(code), 0664) 76 | if err != nil { 77 | return nil 78 | } 79 | } 80 | return nil 81 | } 82 | -------------------------------------------------------------------------------- /tygo/iota.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "regexp" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | var iotaRegexp = regexp.MustCompile(`\biota\b`) 10 | 11 | func isProbablyIotaType(valueString string) bool { 12 | return !strings.ContainsAny(valueString, "\"`") && iotaRegexp.MatchString(valueString) 13 | } 14 | 15 | func replaceIotaValue(valueString string, iotaValue int) string { 16 | return iotaRegexp.ReplaceAllLiteralString(valueString, strconv.Itoa(iotaValue)) 17 | } 18 | -------------------------------------------------------------------------------- /tygo/package_generator.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | "strings" 7 | ) 8 | 9 | // generateFile writes the generated code for a single file to the given strings.Builder. 10 | func (g *PackageGenerator) generateFile(s *strings.Builder, file *ast.File, filepath string) { 11 | first := true 12 | 13 | ast.Inspect(file, func(n ast.Node) bool { 14 | switch x := n.(type) { 15 | 16 | // GenDecl can be an import, type, var, or const expression 17 | case *ast.GenDecl: 18 | if x.Tok == token.IMPORT { 19 | return false 20 | } 21 | isEmit := false 22 | if x.Tok == token.VAR { 23 | isEmit = g.isEmitVar(x) 24 | if !isEmit { 25 | return false 26 | } 27 | } 28 | 29 | if first { 30 | if filepath != "" { 31 | g.writeFileSourceHeader(s, filepath, file) 32 | } 33 | first = false 34 | } 35 | if isEmit { 36 | g.emitVar(s, x) 37 | return false 38 | } 39 | g.writeGroupDecl(s, x) 40 | return false 41 | } 42 | return true 43 | }) 44 | } 45 | 46 | func (g *PackageGenerator) Generate() (string, error) { 47 | s := new(strings.Builder) 48 | 49 | g.writeFileCodegenHeader(s) 50 | g.writeFileFrontmatter(s) 51 | 52 | filepaths := g.GoFiles 53 | 54 | for i, file := range g.pkg.Syntax { 55 | if g.conf.IsFileIgnored(filepaths[i]) { 56 | continue 57 | } 58 | 59 | g.generateFile(s, file, filepaths[i]) 60 | } 61 | 62 | return s.String(), nil 63 | } 64 | -------------------------------------------------------------------------------- /tygo/testdata/fixtures/directive.md: -------------------------------------------------------------------------------- 1 | This fixture is here to reproduce Github issue #26. 2 | 3 | ```go 4 | // Comment above a directive 5 | // 6 | //go:foo 7 | //go:bar 8 | const SomeValue = 3 //comment:test 9 | 10 | // Empty Comment 11 | const AnotherValue = 4 // 12 | 13 | //go:something 14 | const DirectiveOnly = 5 15 | 16 | // RepoIndexerType specifies the repository indexer type 17 | type RepoIndexerType int //revive:disable-line:exported 18 | 19 | const ( 20 | // RepoIndexerTypeCode code indexer 21 | RepoIndexerTypeCode RepoIndexerType = iota // 0 22 | // RepoIndexerTypeStats repository stats indexer 23 | RepoIndexerTypeStats // 1 24 | ) 25 | 26 | const A = "a" 27 | const B = "a" 28 | const C = "c" 29 | ``` 30 | 31 | ```ts 32 | /** 33 | * Comment above a directive 34 | */ 35 | export const SomeValue = 3; 36 | /** 37 | * Empty Comment 38 | */ 39 | export const AnotherValue = 4; 40 | 41 | export const DirectiveOnly = 5; 42 | /** 43 | * RepoIndexerType specifies the repository indexer type 44 | */ 45 | export type RepoIndexerType = number /* int */; 46 | /** 47 | * RepoIndexerTypeCode code indexer 48 | */ 49 | export const RepoIndexerTypeCode: RepoIndexerType = 0; // 0 50 | /** 51 | * RepoIndexerTypeStats repository stats indexer 52 | */ 53 | export const RepoIndexerTypeStats: RepoIndexerType = 1; // 1 54 | export const A = "a"; 55 | export const B = "a"; 56 | export const C = "c"; 57 | ``` -------------------------------------------------------------------------------- /tygo/testdata/fixtures/emit.md: -------------------------------------------------------------------------------- 1 | ```go 2 | // emit directive on a string literal emits that value. 3 | // 4 | //tygo:emit 5 | var _ = `export type OtherStructAsTuple=[ 6 | a:number, 7 | b:number, 8 | c:string, 9 | ] 10 | ` 11 | 12 | //tygo:emit This has no effect, only strings. 13 | var _ = 12 14 | 15 | // a non-string var is ignored. A var with no comment is ignored. 16 | 17 | var foo = " " 18 | 19 | // CustomMarshalled illustrates getting tygo to emit literal text 20 | // This solves the problem of a struct field being marshalled into a tuple. 21 | // 22 | // emit directive on a struct emits the remainder of the directive line 23 | // 24 | //tygo:emit export type StructAsTuple=[a:number, b:number, c:string] 25 | type CustomMarshalled struct { 26 | Content []StructAsTuple `json:"content"` 27 | } 28 | 29 | //tygo:emit export type Genre = "novel" | "crime" | "fantasy" 30 | type Book struct { 31 | Title string `json:"title"` 32 | Genre string `json:"genre" tstype:"Genre"` 33 | } 34 | ``` 35 | 36 | ```ts 37 | export type OtherStructAsTuple=[ 38 | a:number, 39 | b:number, 40 | c:string, 41 | ] 42 | 43 | export type StructAsTuple=[a:number, b:number, c:string] 44 | /** 45 | * CustomMarshalled illustrates getting tygo to emit literal text 46 | * This solves the problem of a struct field being marshalled into a tuple. 47 | * emit directive on a struct emits the remainder of the directive line 48 | */ 49 | export interface CustomMarshalled { 50 | content: StructAsTuple[]; 51 | } 52 | export type Genre = "novel" | "crime" | "fantasy" 53 | 54 | export interface Book { 55 | title: string; 56 | genre: Genre; 57 | } 58 | ``` -------------------------------------------------------------------------------- /tygo/testdata/fixtures/generic.md: -------------------------------------------------------------------------------- 1 | # Union types and empty interfaces and types 2 | ```yaml 3 | fallback_type: "unknown" 4 | ``` 5 | 6 | ```go 7 | // Comment for UnionType 8 | type UnionType interface { 9 | // Comment for fields are possible 10 | uint64 | string | *bool // comment after 11 | 12 | // Comment for a method 13 | SomeMethod() string 14 | } 15 | 16 | type Derived interface { 17 | ~int | string // Line comment 18 | } 19 | 20 | type Any interface { 21 | string | any 22 | } 23 | 24 | type Empty interface{} 25 | 26 | type Something any 27 | 28 | type EmptyStruct struct{} 29 | ``` 30 | 31 | ```ts 32 | /** 33 | * Comment for UnionType 34 | */ 35 | export type UnionType = 36 | /** 37 | * Comment for fields are possible 38 | */ 39 | number /* uint64 */ | string | boolean | undefined // comment after 40 | ; 41 | export type Derived = 42 | number /* int */ | string // Line comment 43 | ; 44 | export type Any = 45 | string | unknown; 46 | export type Empty = unknown; 47 | export type Something = any; 48 | export interface EmptyStruct { 49 | } 50 | ``` 51 | 52 | # Values and pointers 53 | 54 | ```yaml 55 | fallback_type: "unknown" 56 | ``` 57 | 58 | ```go 59 | 60 | type ValAndPtr[V any, PT *V, Unused ~uint64] struct { 61 | Val V 62 | // Comment for ptr field 63 | Ptr PT // ptr line comment 64 | } 65 | 66 | type ABCD[A, B string, C UnionType, D int64 | bool] struct { 67 | A A `json:"a"` 68 | B B `json:"b"` 69 | C C `json:"c"` 70 | D D `json:"d"` 71 | } 72 | 73 | type Foo[A string | uint64, B *A] struct { 74 | Bar A 75 | Boo B 76 | } 77 | 78 | type WithFooGenericTypeArg[A Foo[string, *string]] struct { 79 | SomeField A `json:"some_field"` 80 | } 81 | 82 | // Should not be output as it's a function 83 | func (f Foo[int, Derived]) DoSomething() { 84 | panic("something") 85 | } 86 | ``` 87 | 88 | ```ts 89 | export interface ValAndPtr { 90 | Val: V; 91 | /** 92 | * Comment for ptr field 93 | */ 94 | Ptr: PT; // ptr line comment 95 | } 96 | export interface ABCD { 97 | a: A; 98 | b: B; 99 | c: C; 100 | d: D; 101 | } 102 | export interface Foo { 103 | Bar: A; 104 | Boo: B; 105 | } 106 | export interface WithFooGenericTypeArg> { 107 | some_field: A; 108 | } 109 | ``` 110 | 111 | # Single 112 | 113 | ```go 114 | type Single[S string | uint] struct { 115 | Field S 116 | } 117 | 118 | type SingleSpecific = Single[string] 119 | ``` 120 | 121 | ```ts 122 | export interface Single { 123 | Field: S; 124 | } 125 | export type SingleSpecific = Single; 126 | ``` 127 | 128 | # Any field 129 | 130 | Example for https://github.com/gzuidhof/tygo/issues/65. 131 | ```go 132 | type AnyStructField[T any] struct { 133 | Value T 134 | SomeField string 135 | } 136 | ``` 137 | ```ts 138 | export interface AnyStructField { 139 | Value: T; 140 | SomeField: string; 141 | } 142 | ``` 143 | 144 | ```go 145 | type JsonArray[T any] []T 146 | ``` 147 | 148 | ```ts 149 | export type JsonArray = T[]; 150 | ``` -------------------------------------------------------------------------------- /tygo/testdata/fixtures/inheritance.md: -------------------------------------------------------------------------------- 1 | ```go 2 | type Base struct { 3 | Name string `json:"name"` 4 | } 5 | 6 | type Base2[T string | int] struct { 7 | ID T `json:"id"` 8 | } 9 | 10 | type Base3[T string, X int] struct { 11 | Class T `json:"class"` 12 | Level X `json:"level"` 13 | } 14 | 15 | type Other[T int, X string] struct { 16 | *Base `tstype:",extends,required"` 17 | Base2[T] `tstype:",extends"` 18 | *Base3[X, T] `tstype:",extends"` 19 | OtherWithBase Base ` json:"otherWithBase"` 20 | OtherWithBase2 Base2[X] ` json:"otherWithBase2"` 21 | OtherValue string ` json:"otherValue"` 22 | Author bookapp.AuthorWithInheritance[T] `tstype:"bookapp.AuthorWithInheritance" json:"author"` 23 | bookapp.Book `tstype:",extends"` 24 | TextBook *bookapp.TextBook[T] `tstype:",extends,required"` 25 | } 26 | ``` 27 | 28 | ```ts 29 | export interface Base { 30 | name: string; 31 | } 32 | export interface Base2 { 33 | id: T; 34 | } 35 | export interface Base3 { 36 | class: T; 37 | level: X; 38 | } 39 | export interface Other extends Base, Base2, Partial>, bookapp.Book, bookapp.TextBook { 40 | otherWithBase: Base; 41 | otherWithBase2: Base2; 42 | otherValue: string; 43 | author: bookapp.AuthorWithInheritance; 44 | } 45 | ``` -------------------------------------------------------------------------------- /tygo/testdata/fixtures/simple.md: -------------------------------------------------------------------------------- 1 | ```go 2 | type MyUint8 uint8 3 | type MyInt int 4 | type MyString string 5 | type MyAny any 6 | 7 | // Should be a number in TypeScript. 8 | type MyRune rune 9 | ``` 10 | 11 | ```ts 12 | export type MyUint8 = number /* uint8 */; 13 | export type MyInt = number /* int */; 14 | export type MyString = string; 15 | export type MyAny = any; 16 | /** 17 | * Should be a number in TypeScript. 18 | */ 19 | export type MyRune = number /* rune */; 20 | ``` 21 | 22 | 23 | Struct with some comments 24 | ```go 25 | // Comment for a struct 26 | type MyStruct struct { 27 | SomeField any `json:"some_field"` 28 | // Comment for a field 29 | OtherField bool // Comment after line 30 | FieldWithImportedType some.Type 31 | } 32 | ``` 33 | 34 | ```ts 35 | /** 36 | * Comment for a struct 37 | */ 38 | export interface MyStruct { 39 | some_field: any; 40 | /** 41 | * Comment for a field 42 | */ 43 | OtherField: boolean; // Comment after line 44 | FieldWithImportedType: any /* some.Type */; 45 | } 46 | ``` 47 | 48 | No preserve comments 49 | ```yaml 50 | preserve_comments: "none" 51 | ``` 52 | 53 | ```go 54 | // Foo 55 | type MyValue int // Bar 56 | ``` 57 | 58 | ```ts 59 | export type MyValue = number /* int */; 60 | ``` 61 | 62 | Empty file 63 | ```go 64 | ``` 65 | 66 | ```ts 67 | ``` 68 | 69 | Unexported 70 | 71 | ```go 72 | const myValue = 3 73 | ``` 74 | 75 | ```ts 76 | ``` -------------------------------------------------------------------------------- /tygo/write.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "go/ast" 7 | "go/token" 8 | "regexp" 9 | "strconv" 10 | "strings" 11 | 12 | "github.com/fatih/structtag" 13 | ) 14 | 15 | var validJSNameRegexp = regexp.MustCompile(`(?m)^[\pL_][\pL\pN_]*$`) 16 | var backquoteEscapeRegexp = regexp.MustCompile(`([$\\])`) 17 | var octalPrefixRegexp = regexp.MustCompile(`^0[0-7]`) 18 | var unicode8Regexp = regexp.MustCompile(`\\\\|\\U[\da-fA-F]{8}`) 19 | 20 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence#table 21 | var jsNumberOperatorPrecedence = map[token.Token]int{ 22 | token.MUL: 6, 23 | token.QUO: 6, 24 | token.REM: 6, 25 | token.ADD: 5, 26 | token.SUB: 5, 27 | token.SHL: 4, 28 | token.SHR: 4, 29 | token.AND: 3, 30 | token.AND_NOT: 3, 31 | token.OR: 2, 32 | token.XOR: 1, 33 | } 34 | 35 | func validJSName(n string) bool { 36 | return validJSNameRegexp.MatchString(n) 37 | } 38 | 39 | func getIdent(s string) string { 40 | switch s { 41 | case "bool": 42 | return "boolean" 43 | case "int", "int8", "int16", "int32", "int64", 44 | "uint", "uint8", "uint16", "uint32", "uint64", 45 | "float32", "float64", 46 | "complex64", "complex128", 47 | "rune": 48 | return "number /* " + s + " */" 49 | } 50 | return s 51 | } 52 | 53 | func (g *PackageGenerator) writeIndent(s *strings.Builder, depth int) { 54 | for i := 0; i < depth; i++ { 55 | s.WriteString(g.conf.Indent) 56 | } 57 | } 58 | 59 | func (g *PackageGenerator) writeType( 60 | s *strings.Builder, 61 | t ast.Expr, 62 | p ast.Expr, 63 | depth int, 64 | optionalParens bool, 65 | ) { 66 | // log.Println("writeType:", reflect.TypeOf(t), t) 67 | switch t := t.(type) { 68 | case *ast.StarExpr: 69 | if optionalParens { 70 | s.WriteByte('(') 71 | } 72 | g.writeType(s, t.X, t, depth, false) 73 | s.WriteString(" | undefined") 74 | if optionalParens { 75 | s.WriteByte(')') 76 | } 77 | case *ast.ArrayType: 78 | if v, ok := t.Elt.(*ast.Ident); ok && v.String() == "byte" { 79 | s.WriteString("string") 80 | break 81 | } 82 | g.writeType(s, t.Elt, t, depth, true) 83 | s.WriteString("[]") 84 | case *ast.StructType: 85 | s.WriteString("{\n") 86 | g.writeStructFields(s, t.Fields.List, depth+1) 87 | g.writeIndent(s, depth+1) 88 | s.WriteByte('}') 89 | case *ast.Ident: 90 | if t.String() == "any" { 91 | s.WriteString(getIdent(g.conf.FallbackType)) 92 | } else { 93 | s.WriteString(getIdent(t.String())) 94 | } 95 | case *ast.SelectorExpr: 96 | // e.g. `time.Time` 97 | longType := fmt.Sprintf("%s.%s", t.X, t.Sel) 98 | mappedTsType, ok := g.conf.TypeMappings[longType] 99 | if ok { 100 | s.WriteString(mappedTsType) 101 | } else { // For unknown types we use the fallback type 102 | s.WriteString(g.conf.FallbackType) 103 | s.WriteString(" /* ") 104 | s.WriteString(longType) 105 | s.WriteString(" */") 106 | } 107 | case *ast.MapType: 108 | s.WriteString("{ [key: ") 109 | g.writeType(s, t.Key, t, depth, false) 110 | s.WriteString("]: ") 111 | g.writeType(s, t.Value, t, depth, false) 112 | s.WriteByte('}') 113 | case *ast.BasicLit: 114 | switch t.Kind { 115 | case token.INT: 116 | if octalPrefixRegexp.MatchString(t.Value) { 117 | t.Value = "0o" + t.Value[1:] 118 | } 119 | case token.CHAR: 120 | var char rune 121 | if strings.HasPrefix(t.Value, `'\x`) || 122 | strings.HasPrefix(t.Value, `'\u`) || 123 | strings.HasPrefix(t.Value, `'\U`) { 124 | i32, err := strconv.ParseInt(t.Value[3:len(t.Value)-1], 16, 32) 125 | if err != nil { 126 | panic(err) 127 | } 128 | char = rune(i32) 129 | } else { 130 | var data []byte 131 | data = append(data, '"') 132 | data = append(data, []byte(t.Value[1:len(t.Value)-1])...) 133 | data = append(data, '"') 134 | var s string 135 | err := json.Unmarshal(data, &s) 136 | if err != nil { 137 | panic(err) 138 | } 139 | char = []rune(s)[0] 140 | } 141 | if char > 0xFFFF { 142 | t.Value = fmt.Sprintf("0x%08X /* %s */", char, t.Value) 143 | } else { 144 | t.Value = fmt.Sprintf("0x%04X /* %s */", char, t.Value) 145 | } 146 | case token.STRING: 147 | if strings.HasPrefix(t.Value, "`") { 148 | t.Value = backquoteEscapeRegexp.ReplaceAllString(t.Value, `\$1`) 149 | } else { 150 | t.Value = unicode8Regexp.ReplaceAllStringFunc(t.Value, func(s string) string { 151 | if len(s) == 10 { 152 | s = fmt.Sprintf("\\u{%s}", strings.ToUpper(s[2:])) 153 | } 154 | return s 155 | }) 156 | } 157 | } 158 | s.WriteString(t.Value) 159 | case *ast.ParenExpr: 160 | s.WriteByte('(') 161 | g.writeType(s, t.X, t, depth, false) 162 | s.WriteByte(')') 163 | case *ast.BinaryExpr: 164 | inParen := false 165 | switch p := p.(type) { 166 | case *ast.BinaryExpr: 167 | if jsNumberOperatorPrecedence[t.Op] < jsNumberOperatorPrecedence[p.Op] { 168 | inParen = true 169 | } 170 | } 171 | if inParen { 172 | s.WriteByte('(') 173 | } 174 | g.writeType(s, t.X, t, depth, false) 175 | s.WriteByte(' ') 176 | if t.Op == token.AND_NOT { 177 | s.WriteString("& ~") 178 | } else { 179 | s.WriteString(t.Op.String()) 180 | s.WriteByte(' ') 181 | } 182 | g.writeType(s, t.Y, t, depth, false) 183 | if inParen { 184 | s.WriteByte(')') 185 | } 186 | case *ast.InterfaceType: 187 | g.writeInterfaceFields(s, t.Methods.List, depth+1) 188 | case *ast.CallExpr, *ast.FuncType, *ast.ChanType: 189 | s.WriteString(g.conf.FallbackType) 190 | case *ast.UnaryExpr: 191 | switch t.Op { 192 | case token.TILDE: 193 | // We just ignore the tilde token, in Typescript extended types are 194 | // put into the generic typing itself, which we can't support yet. 195 | g.writeType(s, t.X, t, depth, false) 196 | case token.XOR: 197 | s.WriteString("~") 198 | g.writeType(s, t.X, t, depth, false) 199 | case token.ADD, token.SUB, token.NOT: 200 | s.WriteString(t.Op.String()) 201 | g.writeType(s, t.X, t, depth, false) 202 | default: 203 | err := fmt.Errorf("unhandled unary expr: %v\n %T", t, t) 204 | fmt.Println(err) 205 | panic(err) 206 | } 207 | case *ast.IndexListExpr: 208 | g.writeType(s, t.X, t, depth, false) 209 | s.WriteByte('<') 210 | for i, index := range t.Indices { 211 | g.writeType(s, index, t, depth, false) 212 | if i != len(t.Indices)-1 { 213 | s.WriteString(", ") 214 | } 215 | } 216 | s.WriteByte('>') 217 | case *ast.IndexExpr: 218 | g.writeType(s, t.X, t, depth, false) 219 | s.WriteByte('<') 220 | g.writeType(s, t.Index, t, depth, false) 221 | s.WriteByte('>') 222 | default: 223 | err := fmt.Errorf("unhandled: %s\n %T", t, t) 224 | fmt.Println(err) 225 | panic(err) 226 | } 227 | } 228 | 229 | func (g *PackageGenerator) writeTypeParamsFields(s *strings.Builder, fields []*ast.Field) { 230 | s.WriteByte('<') 231 | for i, f := range fields { 232 | for j, ident := range f.Names { 233 | s.WriteString(ident.Name) 234 | s.WriteString(" extends ") 235 | g.writeType(s, f.Type, nil, 0, true) 236 | 237 | if i != len(fields)-1 || j != len(f.Names)-1 { 238 | s.WriteString(", ") 239 | } 240 | } 241 | } 242 | s.WriteByte('>') 243 | } 244 | 245 | func (g *PackageGenerator) writeInterfaceFields( 246 | s *strings.Builder, 247 | fields []*ast.Field, 248 | depth int, 249 | ) { 250 | // Usually interfaces in Golang don't have fields, but generic (union) interfaces we can map to Typescript. 251 | 252 | if len(fields) == 0 { // Type without any fields (probably only has methods) 253 | s.WriteString(g.conf.FallbackType) 254 | return 255 | } 256 | 257 | didContainNonFuncFields := false 258 | for _, f := range fields { 259 | if _, isFunc := f.Type.(*ast.FuncType); isFunc { 260 | continue 261 | } 262 | if didContainNonFuncFields { 263 | s.WriteString(" &\n") 264 | } else { 265 | s.WriteByte( 266 | '\n', 267 | ) // We need to write a newline so comments of generic components render nicely. 268 | didContainNonFuncFields = true 269 | } 270 | 271 | if g.PreserveTypeComments() { 272 | g.writeCommentGroupIfNotNil(s, f.Doc, depth+1) 273 | } 274 | g.writeIndent(s, depth+1) 275 | g.writeType(s, f.Type, nil, depth, false) 276 | 277 | if f.Comment != nil && g.PreserveTypeComments() { 278 | s.WriteString(" // ") 279 | s.WriteString(f.Comment.Text()) 280 | } 281 | } 282 | 283 | if !didContainNonFuncFields { 284 | s.WriteString(g.conf.FallbackType) 285 | } 286 | } 287 | 288 | func (g *PackageGenerator) writeStructFields(s *strings.Builder, fields []*ast.Field, depth int) { 289 | for _, f := range fields { 290 | // fmt.Println(f.Type) 291 | optional := false 292 | required := false 293 | readonly := false 294 | 295 | var fieldName string 296 | if len(f.Names) == 0 { // anonymous field 297 | if name, valid := getAnonymousFieldName(f.Type); valid { 298 | fieldName = name 299 | } 300 | } 301 | if len(f.Names) != 0 && f.Names[0] != nil && len(f.Names[0].Name) != 0 { 302 | fieldName = f.Names[0].Name 303 | } 304 | if len(fieldName) == 0 || 'A' > fieldName[0] || fieldName[0] > 'Z' { 305 | continue 306 | } 307 | 308 | var name string 309 | var tstype string 310 | if f.Tag != nil { 311 | tags, err := structtag.Parse(f.Tag.Value[1 : len(f.Tag.Value)-1]) 312 | if err != nil { 313 | panic(err) 314 | } 315 | 316 | jsonTag, err := tags.Get("json") 317 | if err == nil { 318 | name = jsonTag.Name 319 | if name == "-" { 320 | continue 321 | } 322 | 323 | optional = jsonTag.HasOption("omitempty") || jsonTag.HasOption("omitzero") 324 | } 325 | yamlTag, err := tags.Get("yaml") 326 | if err == nil { 327 | name = yamlTag.Name 328 | if name == "-" { 329 | continue 330 | } 331 | 332 | optional = yamlTag.HasOption("omitempty") 333 | } 334 | 335 | tstypeTag, err := tags.Get("tstype") 336 | if err == nil { 337 | tstype = tstypeTag.Name 338 | if tstype == "-" || tstypeTag.HasOption("extends") { 339 | continue 340 | } 341 | required = tstypeTag.HasOption("required") 342 | readonly = tstypeTag.HasOption("readonly") 343 | } 344 | } 345 | 346 | if len(name) == 0 { 347 | if g.conf.Flavor == "yaml" { 348 | name = strings.ToLower(fieldName) 349 | } else { 350 | name = fieldName 351 | } 352 | } 353 | 354 | if g.PreserveTypeComments() { 355 | g.writeCommentGroupIfNotNil(s, f.Doc, depth+1) 356 | } 357 | 358 | g.writeIndent(s, depth+1) 359 | quoted := !validJSName(name) 360 | if quoted { 361 | s.WriteByte('\'') 362 | } 363 | if readonly { 364 | s.WriteString("readonly ") 365 | } 366 | s.WriteString(name) 367 | if quoted { 368 | s.WriteByte('\'') 369 | } 370 | 371 | switch t := f.Type.(type) { 372 | case *ast.StarExpr: 373 | optional = !required 374 | f.Type = t.X 375 | } 376 | 377 | if optional && g.conf.OptionalType == "undefined" { 378 | s.WriteByte('?') 379 | } 380 | 381 | s.WriteString(": ") 382 | 383 | if tstype == "" { 384 | g.writeType(s, f.Type, nil, depth, false) 385 | if optional && g.conf.OptionalType == "null" { 386 | s.WriteString(" | null") 387 | } 388 | } else { 389 | s.WriteString(tstype) 390 | } 391 | s.WriteByte(';') 392 | 393 | if f.Comment != nil && g.PreserveTypeComments() { 394 | // Line comment is present, that means a comment after the field. 395 | s.WriteString(" // ") 396 | s.WriteString(f.Comment.Text()) 397 | } else { 398 | s.WriteByte('\n') 399 | } 400 | 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /tygo/write_comment.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "go/ast" 5 | "strings" 6 | ) 7 | 8 | func (g *PackageGenerator) PreserveDocComments() bool { 9 | return g.conf.PreserveComments == "default" 10 | } 11 | 12 | func (g *PackageGenerator) PreserveTypeComments() bool { 13 | return g.conf.PreserveComments == "types" || g.conf.PreserveComments == "default" 14 | } 15 | 16 | func (g *PackageGenerator) writeCommentGroupIfNotNil(s *strings.Builder, f *ast.CommentGroup, depth int) { 17 | if f != nil { 18 | g.writeCommentGroup(s, f, depth) 19 | } 20 | } 21 | 22 | func (c *PackageGenerator) writeDirective(s *strings.Builder, cg *ast.CommentGroup) { 23 | for _, cm := range cg.List { 24 | if strings.HasPrefix(cm.Text, "//tygo:emit") { 25 | // remove the separator whitespace but leave extra whitespace for indentation 26 | s.WriteString(strings.TrimPrefix(cm.Text, "//tygo:emit")[1:]) 27 | s.WriteString("\n") 28 | } 29 | } 30 | } 31 | 32 | func (g *PackageGenerator) writeCommentGroup(s *strings.Builder, cg *ast.CommentGroup, depth int) { 33 | docLines := strings.Split(cg.Text(), "\n") 34 | 35 | g.writeDirective(s, cg) 36 | if len(cg.List) > 0 && cg.Text() == "" { // This is a directive comment like //go:embed 37 | s.WriteByte('\n') 38 | return 39 | } 40 | 41 | if depth != 0 { 42 | g.writeIndent(s, depth) 43 | } 44 | s.WriteString("/**\n") 45 | 46 | for _, c := range docLines { 47 | if len(strings.TrimSpace(c)) == 0 { 48 | continue 49 | } 50 | g.writeIndent(s, depth) 51 | s.WriteString(" * ") 52 | c = strings.ReplaceAll(c, "*/", "*\\/") // An edge case: a // comment can contain */ 53 | s.WriteString(c) 54 | s.WriteByte('\n') 55 | } 56 | g.writeIndent(s, depth) 57 | s.WriteString(" */\n") 58 | } 59 | 60 | // Outputs a comment like // hello world 61 | func (g *PackageGenerator) writeSingleLineComment(s *strings.Builder, cg *ast.CommentGroup) { 62 | text := cg.Text() 63 | 64 | if len(cg.List) > 0 && cg.Text() == "" { // This is a directive comment like //go:embed 65 | s.WriteByte('\n') 66 | return 67 | } 68 | 69 | s.WriteString(" // " + text) 70 | 71 | if len(text) == 0 { 72 | // This is an empty comment like // 73 | s.WriteByte('\n') 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tygo/write_headers.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "go/ast" 5 | "path/filepath" 6 | "strings" 7 | ) 8 | 9 | func (g *PackageGenerator) writeFileCodegenHeader(w *strings.Builder) { 10 | w.WriteString("// Code generated by tygo. DO NOT EDIT.\n") 11 | } 12 | 13 | func (g *PackageGenerator) writeFileFrontmatter(w *strings.Builder) { 14 | if g.conf.Frontmatter != "" { 15 | w.WriteString(g.conf.Frontmatter) 16 | } 17 | } 18 | 19 | func (g *PackageGenerator) writeFileSourceHeader(w *strings.Builder, path string, file *ast.File) { 20 | w.WriteString("\n//////////\n// source: ") 21 | w.WriteString(filepath.Base(path)) 22 | w.WriteString("\n") 23 | 24 | if file.Doc != nil && g.PreserveDocComments() { 25 | w.WriteString("/*\n") 26 | w.WriteString(file.Doc.Text()) 27 | w.WriteString("*/\n") 28 | } 29 | w.WriteString("\n") 30 | } 31 | -------------------------------------------------------------------------------- /tygo/write_toplevel.go: -------------------------------------------------------------------------------- 1 | package tygo 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/token" 7 | "strings" 8 | 9 | "github.com/fatih/structtag" 10 | ) 11 | 12 | type groupContext struct { 13 | isGroupedDeclaration bool 14 | doc *ast.CommentGroup 15 | groupValue string 16 | groupType string 17 | iotaValue int 18 | } 19 | 20 | // isEmitVar returns true if dec is a string var with a tygo:emit directive. 21 | func (g *PackageGenerator) isEmitVar(dec *ast.GenDecl) bool { 22 | if dec.Tok != token.VAR || dec.Doc == nil { 23 | return false 24 | } 25 | 26 | for _, c := range dec.Doc.List { 27 | if strings.HasPrefix(c.Text, "//tygo:emit") { 28 | // we know it's VAR so asserting *ast.ValueSpec is OK. 29 | v, ok := dec.Specs[0].(*ast.ValueSpec).Values[0].(*ast.BasicLit) 30 | if !ok { 31 | return false 32 | } 33 | return v.Kind == token.STRING 34 | } 35 | } 36 | return false 37 | } 38 | 39 | // emitVar emits the text associated with dec, which is assumes to be a string var with a 40 | // tygo:emit directive, as tested by isEmitVar. 41 | func (g *PackageGenerator) emitVar(s *strings.Builder, dec *ast.GenDecl) { 42 | v := dec.Specs[0].(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value 43 | if len(v) < 2 { 44 | return 45 | } 46 | s.WriteString(v[1:len(v)-1] + "\n") 47 | } 48 | func (g *PackageGenerator) writeGroupDecl(s *strings.Builder, decl *ast.GenDecl) { 49 | // This checks whether the declaration is a group declaration like: 50 | // const ( 51 | // X = 3 52 | // Y = "abc" 53 | // ) 54 | isGroupedDeclaration := len(decl.Specs) > 1 55 | 56 | if !isGroupedDeclaration && g.PreserveTypeComments() { 57 | g.writeCommentGroupIfNotNil(s, decl.Doc, 0) 58 | } 59 | 60 | // We need a bit of state to handle syntax like 61 | // const ( 62 | // X SomeType = iota 63 | // _ 64 | // Y 65 | // Foo string = "Foo" 66 | // _ 67 | // AlsoFoo 68 | // ) 69 | group := &groupContext{ 70 | isGroupedDeclaration: len(decl.Specs) > 1, 71 | doc: decl.Doc, 72 | groupType: "", 73 | groupValue: "", 74 | iotaValue: -1, 75 | } 76 | 77 | for _, spec := range decl.Specs { 78 | g.writeSpec(s, spec, group) 79 | } 80 | } 81 | 82 | func (g *PackageGenerator) writeSpec(s *strings.Builder, spec ast.Spec, group *groupContext) { 83 | // e.g. "type Foo struct {}" or "type Bar = string" 84 | ts, ok := spec.(*ast.TypeSpec) 85 | if ok && ts.Name.IsExported() { 86 | g.writeTypeSpec(s, ts, group) 87 | } 88 | 89 | // e.g. "const Foo = 123" 90 | vs, ok := spec.(*ast.ValueSpec) 91 | if ok { 92 | g.writeValueSpec(s, vs, group) 93 | } 94 | } 95 | 96 | // Writing of type specs, which are expressions like 97 | // `type X struct { ... }` 98 | // or 99 | // `type Bar = string` 100 | func (g *PackageGenerator) writeTypeSpec( 101 | s *strings.Builder, 102 | ts *ast.TypeSpec, 103 | group *groupContext, 104 | ) { 105 | if ts.Doc != nil && 106 | g.PreserveTypeComments() { // The spec has its own comment, which overrules the grouped comment. 107 | g.writeCommentGroup(s, ts.Doc, 0) 108 | } else if group.isGroupedDeclaration && g.PreserveTypeComments() { 109 | g.writeCommentGroupIfNotNil(s, group.doc, 0) 110 | } 111 | 112 | st, isStruct := ts.Type.(*ast.StructType) 113 | if isStruct { 114 | s.WriteString("export interface ") 115 | s.WriteString(ts.Name.Name) 116 | if g.conf.Extends != "" { 117 | s.WriteString(" extends ") 118 | s.WriteString(g.conf.Extends) 119 | } 120 | 121 | if ts.TypeParams != nil { 122 | g.writeTypeParamsFields(s, ts.TypeParams.List) 123 | } 124 | 125 | g.writeTypeInheritanceSpec(s, st.Fields.List) 126 | s.WriteString(" {\n") 127 | g.writeStructFields(s, st.Fields.List, 0) 128 | s.WriteString("}") 129 | } 130 | 131 | id, isIdent := ts.Type.(*ast.Ident) 132 | if isIdent { 133 | s.WriteString("export type ") 134 | s.WriteString(ts.Name.Name) 135 | s.WriteString(" = ") 136 | s.WriteString(getIdent(id.Name)) 137 | s.WriteString(";") 138 | } 139 | 140 | if !isStruct && !isIdent { 141 | s.WriteString("export type ") 142 | s.WriteString(ts.Name.Name) 143 | 144 | if ts.TypeParams != nil { 145 | g.writeTypeParamsFields(s, ts.TypeParams.List) 146 | } 147 | 148 | s.WriteString(" = ") 149 | g.writeType(s, ts.Type, nil, 0, true) 150 | s.WriteString(";") 151 | 152 | } 153 | 154 | if ts.Comment != nil && g.PreserveTypeComments() { 155 | g.writeSingleLineComment(s, ts.Comment) 156 | } else { 157 | s.WriteString("\n") 158 | } 159 | } 160 | 161 | // Writing of type inheritance specs, which are expressions like 162 | // `type X struct { }` 163 | // `type Y struct { X `tstype:",extends"` }` 164 | // `export interface Y extends X { }` 165 | func (g *PackageGenerator) writeTypeInheritanceSpec(s *strings.Builder, fields []*ast.Field) { 166 | inheritances := make([]string, 0) 167 | for _, f := range fields { 168 | if f.Type != nil && f.Tag != nil { 169 | tags, err := structtag.Parse(f.Tag.Value[1 : len(f.Tag.Value)-1]) 170 | if err != nil { 171 | panic(err) 172 | } 173 | 174 | tstypeTag, err := tags.Get("tstype") 175 | if err != nil || !tstypeTag.HasOption("extends") { 176 | continue 177 | } 178 | 179 | longType, valid := getInheritedType(f.Type, tstypeTag) 180 | if valid { 181 | mappedTsType, ok := g.conf.TypeMappings[longType] 182 | if ok { 183 | inheritances = append(inheritances, mappedTsType) 184 | } else { 185 | // We can't use the fallback type because TypeScript doesn't allow extending "any". 186 | inheritances = append(inheritances, longType) 187 | } 188 | 189 | } 190 | } 191 | } 192 | if len(inheritances) > 0 { 193 | s.WriteString(" extends ") 194 | s.WriteString(strings.Join(inheritances, ", ")) 195 | } 196 | } 197 | 198 | // Writing of value specs, which are exported const expressions like 199 | // const SomeValue = 3 200 | func (g *PackageGenerator) writeValueSpec( 201 | s *strings.Builder, 202 | vs *ast.ValueSpec, 203 | group *groupContext, 204 | ) { 205 | for i, name := range vs.Names { 206 | group.iotaValue = group.iotaValue + 1 207 | if name.Name == "_" { 208 | continue 209 | } 210 | if !name.IsExported() { 211 | continue 212 | } 213 | 214 | if vs.Doc != nil && 215 | g.PreserveTypeComments() { // The spec has its own comment, which overrules the grouped comment. 216 | g.writeCommentGroup(s, vs.Doc, 0) 217 | } else if group.isGroupedDeclaration && g.PreserveTypeComments() { 218 | g.writeCommentGroupIfNotNil(s, group.doc, 0) 219 | } 220 | 221 | hasExplicitValue := len(vs.Values) > i 222 | if hasExplicitValue { 223 | group.groupType = "" 224 | } 225 | 226 | s.WriteString("export const ") 227 | s.WriteString(name.Name) 228 | if vs.Type != nil { 229 | s.WriteString(": ") 230 | 231 | tempSB := &strings.Builder{} 232 | g.writeType(tempSB, vs.Type, nil, 0, true) 233 | typeString := tempSB.String() 234 | 235 | s.WriteString(typeString) 236 | group.groupType = typeString 237 | } else if group.groupType != "" && !hasExplicitValue { 238 | s.WriteString(": ") 239 | s.WriteString(group.groupType) 240 | } 241 | 242 | s.WriteString(" = ") 243 | 244 | if hasExplicitValue { 245 | val := vs.Values[i] 246 | tempSB := &strings.Builder{} 247 | // log.Println("const:", name.Name, reflect.TypeOf(val), val) 248 | g.writeType(tempSB, val, nil, 0, false) 249 | group.groupValue = tempSB.String() 250 | } 251 | 252 | valueString := group.groupValue 253 | if isProbablyIotaType(valueString) { 254 | valueString = replaceIotaValue(valueString, group.iotaValue) 255 | } 256 | s.WriteString(valueString) 257 | 258 | s.WriteByte(';') 259 | 260 | if g.PreserveDocComments() && vs.Comment != nil { 261 | g.writeSingleLineComment(s, vs.Comment) 262 | } else { 263 | s.WriteByte('\n') 264 | } 265 | 266 | } 267 | } 268 | 269 | func getInheritedType(f ast.Expr, tag *structtag.Tag) (name string, valid bool) { 270 | switch ft := f.(type) { 271 | case *ast.Ident: 272 | if ft.Obj != nil && ft.Obj.Decl != nil { 273 | dcl, ok := ft.Obj.Decl.(*ast.TypeSpec) 274 | if ok { 275 | _, isStruct := dcl.Type.(*ast.StructType) 276 | valid = isStruct && dcl.Name.IsExported() 277 | name = dcl.Name.Name 278 | } 279 | } else { 280 | // Types defined in the Go file after the parsed file in the same package 281 | valid = token.IsExported(ft.Name) 282 | name = ft.Name 283 | } 284 | case *ast.IndexExpr: 285 | name, valid = getInheritedType(ft.X, tag) 286 | if valid { 287 | generic := getIdent(ft.Index.(*ast.Ident).Name) 288 | name += fmt.Sprintf("<%s>", generic) 289 | } 290 | case *ast.IndexListExpr: 291 | name, valid = getInheritedType(ft.X, tag) 292 | if valid { 293 | generic := "" 294 | for _, index := range ft.Indices { 295 | generic += fmt.Sprintf("%s, ", getIdent(index.(*ast.Ident).Name)) 296 | } 297 | name += fmt.Sprintf("<%s>", generic[:len(generic)-2]) 298 | } 299 | case *ast.SelectorExpr: 300 | valid = ft.Sel.IsExported() 301 | name = fmt.Sprintf("%s.%s", ft.X, ft.Sel) 302 | case *ast.StarExpr: 303 | name, valid = getInheritedType(ft.X, tag) 304 | if valid { 305 | // If the type is not required, mark as optional inheritance 306 | if !tag.HasOption("required") { 307 | name = fmt.Sprintf("Partial<%s>", name) 308 | } 309 | } 310 | 311 | } 312 | return 313 | } 314 | 315 | func getAnonymousFieldName(f ast.Expr) (name string, valid bool) { 316 | switch ft := f.(type) { 317 | case *ast.Ident: 318 | name = ft.Name 319 | if ft.Obj != nil && ft.Obj.Decl != nil { 320 | dcl, ok := ft.Obj.Decl.(*ast.TypeSpec) 321 | if ok { 322 | valid = dcl.Name.IsExported() 323 | } 324 | } else { 325 | // Types defined in the Go file after the parsed file in the same package 326 | valid = token.IsExported(name) 327 | } 328 | case *ast.IndexExpr: 329 | return getAnonymousFieldName(ft.X) 330 | case *ast.IndexListExpr: 331 | return getAnonymousFieldName(ft.X) 332 | case *ast.SelectorExpr: 333 | valid = ft.Sel.IsExported() 334 | name = ft.Sel.String() 335 | case *ast.StarExpr: 336 | return getAnonymousFieldName(ft.X) 337 | } 338 | 339 | return 340 | } 341 | --------------------------------------------------------------------------------