diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e0871f9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "gomod" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml new file mode 100644 index 0000000..39b4751 --- /dev/null +++ b/.github/workflows/codacy.yml @@ -0,0 +1,61 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '41 5 * * 3' + +permissions: + contents: read + +jobs: + codacy-security-scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + name: Codacy Security Scan + runs-on: ubuntu-latest + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout code + uses: actions/checkout@v3 + + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b + with: + # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository + # You can also omit the token and run the tools that support default configurations + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..b0dedc4 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..0065213 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,28 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Go + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e1913f2..488c212 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: - name: Install Go uses: actions/setup-go@v1 with: - go-version: 1.18.x + go-version: 1.20.x - name: Run GoReleaser uses: goreleaser/goreleaser-action@v1 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f39e84..20de154 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: - name: Install Go uses: actions/setup-go@v1 with: - go-version: 1.18.x + go-version: 1.20.x - name: Checkout code uses: actions/checkout@v2 - name: Lint diff --git a/.golangci.yml b/.golangci.yml index 55c8959..0ea62a7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -46,3 +46,7 @@ issues: - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked exclude-use-default: false + +run: + skip-dirs: + - testData \ No newline at end of file diff --git a/.gomarkdoc.yml b/.gomarkdoc.yml index 78116e9..8fd532d 100644 --- a/.gomarkdoc.yml +++ b/.gomarkdoc.yml @@ -1,10 +1,9 @@ output: "{{.Dir}}/README.md" -header: |+ +header: |- [![Go Report Card](https://goreportcard.com/badge/github.com/Weborama/gomarkdoc)](https://goreportcard.com/report/github.com/Weborama/gomarkdoc) [![GitHub Actions](https://github.com/Weborama/gomarkdoc/workflows/Test/badge.svg)](https://github.com/Weborama/gomarkdoc/actions?query=workflow%3ATest+branch%3Amaster) [![Go Reference](https://pkg.go.dev/badge/github.com/Weborama/gomarkdoc.svg)](https://pkg.go.dev/github.com/Weborama/gomarkdoc) - [![codecov](https://codecov.io/gh/princjef/gomarkdoc/branch/master/graph/badge.svg?token=171XNH5XLT)](https://codecov.io/gh/princjef/gomarkdoc) - + [![codecov](https://codecov.io/gh/Weborama/gomarkdoc/branch/master/graph/badge.svg?token=171XNH5XLT)](https://codecov.io/gh/Weborama/gomarkdoc) repository: url: https://github.com/Weborama/gomarkdoc defaultBranch: master diff --git a/README.md b/README.md index aa0906e..47673e3 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Flags: -c, --check Check the output to see if it matches the generated documentation. --output must be specified to use this. --config string File from which to load configuration (default: .gomarkdoc.yml) -e, --embed Embed documentation into existing markdown files if available, otherwise append to file. + --exclude-dirs strings List of package directories to ignore when producing documentation. --footer string Additional content to inject at the end of each output file. --footer-file string File containing additional content to inject at the end of each output file. -f, --format string Format to use for writing output data. Valid options: github (default), azure-devops, plain (default "github") @@ -68,6 +69,14 @@ gomarkdoc --output doc.md . The gomarkdoc tool supports generating documentation for both local packages and remote ones. To specify a local package, start the name of the package with a period \(.\) or specify an absolute path on the filesystem. All other package signifiers are assumed to be remote packages. You may specify both local and remote packages in the same command invocation as separate arguments. +If you have a project with many packages but you want to skip documentation generation for some, you can use the \-\-exclude\-dirs option. This will remove any matching directories from the list of directories to process. Excluded directories are specified using the same pathing syntax as the packages to process. Multiple expressions may be comma\-separated or specified by using the \-\-exclude\-dirs flag multiple times. + +For example, in this repository we generate documentation for the entire project while excluding our test packages by running: + +``` +gomarkdoc --exclude-dirs ./testData/... ./... +``` + ### Output Redirection By default, the documentation generated by the gomarkdoc command is sent to standard output, where it can be redirected to a file. This can be useful if you want to perform additional modifications to the documentation or send it somewhere other than a file. However, keep in mind that there are some inconsistencies in how various shells/platforms handle redirected command output \(for example, Powershell encodes in UTF\-16, not UTF\-8\). As a result, the \-\-output option described below is recommended for most use cases. @@ -88,44 +97,28 @@ You can see all of the data available to the output template in the PackageSpec The documentation information that is output is formatted using a series of text templates for the various components of the overall documentation which get generated. Higher level templates contain lower level templates, but any template may be replaced with an override template using the \-\-template/\-t option. The full list of templates that may be overridden are: -``` -- file: generates documentation for a file containing one or more - packages, depending on how the tool is configured. This is the - root template for documentation generation. +- file: generates documentation for a file containing one or more packages, depending on how the tool is configured. This is the root template for documentation generation. - package: generates documentation for an entire package. -- type: generates documentation for a single type declaration, as well - as any related functions/methods. +- type: generates documentation for a single type declaration, as well as any related functions/methods. -- func: generates documentation for a single function or method. It may - be referenced from within a type, or directly in the package, - depending on nesting. +- func: generates documentation for a single function or method. It may be referenced from within a type, or directly in the package, depending on nesting. -- value: generates documentation for a single variable or constant - declaration block within a package. +- value: generates documentation for a single variable or constant declaration block within a package. -- index: generates an index of symbols within a package, similar to what - is seen for godoc.org. The index links to types, funcs, - variables, and constants generated by other templates, so it may - need to be overridden as well if any of those templates are - changed in a material way. +- index: generates an index of symbols within a package, similar to what is seen for godoc.org. The index links to types, funcs, variables, and constants generated by other templates, so it may need to be overridden as well if any of those templates are changed in a material way. -- example: generates documentation for a single example for a package or - one of its symbols. The example is generated alongside whichever - symbol it represents, based on the standard naming conventions - outlined in https://blog.golang.org/examples#TOC_4. +- example: generates documentation for a single example for a package or one of its symbols. The example is generated alongside whichever symbol it represents, based on the standard naming conventions outlined in https://blog.golang.org/examples#TOC_4. -- doc: generates the freeform documentation block for any of the above - structures that can contain a documentation section. +- doc: generates the freeform documentation block for any of the above structures that can contain a documentation section. -- import: generates the import code used to pull in a package. -``` +- import: generates the import code used to pull in a package. -Overriding with the \-t option uses a key\-vaule pair mapping a template name to the file containing the contents of the override template to use. Specified template files must exist: +Overriding with the \-\-template\-file option uses a key\-value pair mapping a template name to the file containing the contents of the override template to use. Specified template files must exist: ``` -gomarkdoc -t package=custom-package.gotxt -t doc=custom-doc.gotxt . +gomarkdoc --template-file package=custom-package.gotxt --template-file doc=custom-doc.gotxt . ``` ### Additional Options @@ -245,19 +238,21 @@ Know of another project that is using gomarkdoc? Open an issue with a descriptio ## Index -- [type Renderer](<#type-renderer>) - - [func NewRenderer(opts ...RendererOption) (*Renderer, error)](<#func-newrenderer>) - - [func (out *Renderer) Example(ex *lang.Example) (string, error)](<#func-renderer-example>) - - [func (out *Renderer) File(file *lang.File) (string, error)](<#func-renderer-file>) - - [func (out *Renderer) Func(fn *lang.Func) (string, error)](<#func-renderer-func>) - - [func (out *Renderer) Package(pkg *lang.Package) (string, error)](<#func-renderer-package>) - - [func (out *Renderer) Type(typ *lang.Type) (string, error)](<#func-renderer-type>) -- [type RendererOption](<#type-rendereroption>) - - [func WithFormat(format format.Format) RendererOption](<#func-withformat>) - - [func WithTemplateOverride(name, tmpl string) RendererOption](<#func-withtemplateoverride>) +- [type Renderer](<#Renderer>) + - [func NewRenderer\(opts ...RendererOption\) \(\*Renderer, error\)](<#NewRenderer>) + - [func \(out \*Renderer\) Example\(ex \*lang.Example\) \(string, error\)](<#Renderer.Example>) + - [func \(out \*Renderer\) File\(file \*lang.File\) \(string, error\)](<#Renderer.File>) + - [func \(out \*Renderer\) Func\(fn \*lang.Func\) \(string, error\)](<#Renderer.Func>) + - [func \(out \*Renderer\) Package\(pkg \*lang.Package\) \(string, error\)](<#Renderer.Package>) + - [func \(out \*Renderer\) Type\(typ \*lang.Type\) \(string, error\)](<#Renderer.Type>) +- [type RendererOption](<#RendererOption>) + - [func WithFormat\(format format.Format\) RendererOption](<#WithFormat>) + - [func WithTemplateFunc\(name string, fn any\) RendererOption](<#WithTemplateFunc>) + - [func WithTemplateOverride\(name, tmpl string\) RendererOption](<#WithTemplateOverride>) -## type [Renderer]() + +## type [Renderer]() Renderer provides capabilities for rendering various types of documentation with the configured format and templates. @@ -267,7 +262,8 @@ type Renderer struct { } ``` -### func [NewRenderer]() + +### func [NewRenderer]() ```go func NewRenderer(opts ...RendererOption) (*Renderer, error) @@ -275,7 +271,8 @@ func NewRenderer(opts ...RendererOption) (*Renderer, error) NewRenderer initializes a Renderer configured using the provided options. If nothing special is provided, the created renderer will use the default set of templates and the GitHubFlavoredMarkdown. -### func \(\*Renderer\) [Example]() + +### func \(\*Renderer\) [Example]() ```go func (out *Renderer) Example(ex *lang.Example) (string, error) @@ -283,7 +280,8 @@ func (out *Renderer) Example(ex *lang.Example) (string, error) Example renders an example's documentation to a string. You can change the rendering of the example by overriding the "example" template or one of the templates it references. -### func \(\*Renderer\) [File]() + +### func \(\*Renderer\) [File]() ```go func (out *Renderer) File(file *lang.File) (string, error) @@ -291,7 +289,8 @@ func (out *Renderer) File(file *lang.File) (string, error) File renders a file containing one or more packages to document to a string. You can change the rendering of the file by overriding the "file" template or one of the templates it references. -### func \(\*Renderer\) [Func]() + +### func \(\*Renderer\) [Func]() ```go func (out *Renderer) Func(fn *lang.Func) (string, error) @@ -299,7 +298,8 @@ func (out *Renderer) Func(fn *lang.Func) (string, error) Func renders a function's documentation to a string. You can change the rendering of the package by overriding the "func" template or one of the templates it references. -### func \(\*Renderer\) [Package]() + +### func \(\*Renderer\) [Package]() ```go func (out *Renderer) Package(pkg *lang.Package) (string, error) @@ -307,7 +307,8 @@ func (out *Renderer) Package(pkg *lang.Package) (string, error) Package renders a package's documentation to a string. You can change the rendering of the package by overriding the "package" template or one of the templates it references. -### func \(\*Renderer\) [Type]() + +### func \(\*Renderer\) [Type]() ```go func (out *Renderer) Type(typ *lang.Type) (string, error) @@ -315,7 +316,8 @@ func (out *Renderer) Type(typ *lang.Type) (string, error) Type renders a type's documentation to a string. You can change the rendering of the type by overriding the "type" template or one of the templates it references. -## type [RendererOption]() + +## type [RendererOption]() RendererOption configures the renderer's behavior. @@ -323,7 +325,8 @@ RendererOption configures the renderer's behavior. type RendererOption func(renderer *Renderer) error ``` -### func [WithFormat]() + +### func [WithFormat]() ```go func WithFormat(format format.Format) RendererOption @@ -331,14 +334,24 @@ func WithFormat(format format.Format) RendererOption WithFormat changes the renderer to use the format provided instead of the default format. -### func [WithTemplateOverride]() + +### func [WithTemplateFunc]() ```go -func WithTemplateOverride(name, tmpl string) RendererOption +func WithTemplateFunc(name string, fn any) RendererOption ``` -WithTemplateOverride adds a template that overrides the template with the provided name using the value provided in the tmpl parameter. +WithTemplateFunc adds the provided function with the given name to the list of functions that can be used by the rendering templates. + +Any name collisions between built\-in functions and functions provided here are resolved in favor of the function provided here, so be careful about the naming of your functions to avoid overriding existing behavior unless desired. + +### func [WithTemplateOverride]() +```go +func WithTemplateOverride(name, tmpl string) RendererOption +``` + +WithTemplateOverride adds a template that overrides the template with the provided name using the value provided in the tmpl parameter. Generated by [gomarkdoc]() diff --git a/cmd/gomarkdoc/README.md b/cmd/gomarkdoc/README.md index 926e5d3..aa295fc 100644 --- a/cmd/gomarkdoc/README.md +++ b/cmd/gomarkdoc/README.md @@ -12,9 +12,10 @@ See https://github.com/princjef/gomarkdoc for full documentation of this tool. ## Index -- [type PackageSpec](<#type-packagespec>) +- [type PackageSpec](<#PackageSpec>) + ## type [PackageSpec]() PackageSpec defines the data available to the \-\-output option's template. Information is recomputed for each package generated. @@ -34,6 +35,4 @@ type PackageSpec struct { } ``` - - Generated by [gomarkdoc]() diff --git a/cmd/gomarkdoc/command.go b/cmd/gomarkdoc/command.go index 6bb3bad..5d4e01a 100644 --- a/cmd/gomarkdoc/command.go +++ b/cmd/gomarkdoc/command.go @@ -52,6 +52,7 @@ type commandOptions struct { footerFile string format string tags []string + excludeDirs []string templateOverrides map[string]string templateFileOverrides map[string]string verbosity int @@ -97,6 +98,7 @@ func buildCommand() *cobra.Command { opts.footer = viper.GetString("footer") opts.footerFile = viper.GetString("footerFile") opts.tags = viper.GetStringSlice("tags") + opts.excludeDirs = viper.GetStringSlice("excludeDirs") opts.repository.Remote = viper.GetString("repository.url") opts.repository.DefaultBranch = viper.GetString("repository.defaultBranch") opts.repository.PathFromRoot = viper.GetString("repository.path") @@ -199,6 +201,12 @@ func buildCommand() *cobra.Command { defaultTags(), "Set of build tags to apply when choosing which files to include for documentation generation.", ) + command.Flags().StringSliceVar( + &opts.excludeDirs, + "exclude-dirs", + nil, + "List of package directories to ignore when producing documentation.", + ) command.Flags().CountVarP( &opts.verbosity, "verbose", @@ -249,6 +257,7 @@ func buildCommand() *cobra.Command { _ = viper.BindPFlag("footer", command.Flags().Lookup("footer")) _ = viper.BindPFlag("footerFile", command.Flags().Lookup("footer-file")) _ = viper.BindPFlag("tags", command.Flags().Lookup("tags")) + _ = viper.BindPFlag("excludeDirs", command.Flags().Lookup("exclude-dirs")) _ = viper.BindPFlag("repository.url", command.Flags().Lookup("repository.url")) _ = viper.BindPFlag("repository.defaultBranch", command.Flags().Lookup("repository.default-branch")) _ = viper.BindPFlag("repository.path", command.Flags().Lookup("repository.path")) @@ -303,6 +312,13 @@ func runCommand(paths []string, opts commandOptions) error { specs := getSpecs(paths...) + excluded := getSpecs(opts.excludeDirs...) + if err := validateExcludes(excluded); err != nil { + return err + } + + specs = removeExcludes(specs, excluded) + if err := resolveOutput(specs, outputTmpl); err != nil { return err } @@ -574,13 +590,49 @@ func isIgnoredDir(dirname string) bool { return false } +// validateExcludes checks that the exclude dirs are all directories, not +// packages. +func validateExcludes(specs []*PackageSpec) error { + for _, s := range specs { + if !s.isLocal { + return fmt.Errorf("gomarkdoc: invalid directory specified as an exclude directory: %s", s.ImportPath) + } + } + + return nil +} + +// removeExcludes removes any package specs that were specified as excluded. +func removeExcludes(specs []*PackageSpec, excludes []*PackageSpec) []*PackageSpec { + out := make([]*PackageSpec, 0, len(specs)) + for _, s := range specs { + var exclude bool + for _, e := range excludes { + if !s.isLocal || !e.isLocal { + continue + } + + if r, err := filepath.Rel(s.Dir, e.Dir); err == nil && r == "." { + exclude = true + break + } + } + + if !exclude { + out = append(out, s) + } + } + + return out +} + const ( cwdPathPrefix = "." + string(os.PathSeparator) parentPathPrefix = ".." + string(os.PathSeparator) ) func isLocalPath(path string) bool { - return strings.HasPrefix(path, cwdPathPrefix) || strings.HasPrefix(path, parentPathPrefix) || filepath.IsAbs(path) + return strings.HasPrefix(path, ".") || strings.HasPrefix(path, parentPathPrefix) || filepath.IsAbs(path) } func compare(r1, r2 io.Reader) (bool, error) { diff --git a/cmd/gomarkdoc/command_test.go b/cmd/gomarkdoc/command_test.go index a7d3dc9..6b2bea0 100644 --- a/cmd/gomarkdoc/command_test.go +++ b/cmd/gomarkdoc/command_test.go @@ -15,23 +15,34 @@ import ( var wd, _ = os.Getwd() func TestCommand(t *testing.T) { - is := is.New(t) + tests := []string{ + "./simple", + "./lang/function", + "./docs", + "./untagged", + } - err := os.Chdir(filepath.Join(wd, "../../testData")) - is.NoErr(err) + for _, test := range tests { + t.Run(test, func(t *testing.T) { + is := is.New(t) - os.Args = []string{ - "gomarkdoc", "./simple", - "-o", "{{.Dir}}/README-test.md", - "--repository.url", "https://github.com/Weborama/gomarkdoc", - "--repository.default-branch", "master", - "--repository.path", "/testData/", - } - cleanup("simple") + err := os.Chdir(filepath.Join(wd, "../../testData")) + is.NoErr(err) - main() + os.Args = []string{ + "gomarkdoc", test, + "-o", "{{.Dir}}/README-test.md", + "--repository.url", "https://github.com/Weborama/gomarkdoc", + "--repository.default-branch", "master", + "--repository.path", "/testData/", + } + cleanup(test) - verify(t, "simple") + main() + + verify(t, test) + }) + } } func TestCommand_check(t *testing.T) { @@ -306,26 +317,6 @@ func TestCommand_embed(t *testing.T) { verify(t, "./embed") } -func TestCommand_untagged(t *testing.T) { - is := is.New(t) - - err := os.Chdir(filepath.Join(wd, "../../testData")) - is.NoErr(err) - - os.Args = []string{ - "gomarkdoc", "./untagged", - "-o", "{{.Dir}}/README-test.md", - "--repository.url", "https://github.com/Weborama/gomarkdoc", - "--repository.default-branch", "master", - "--repository.path", "/testData/", - } - cleanup("untagged") - - main() - - verify(t, "./untagged") -} - func TestCompare(t *testing.T) { tests := []struct { b1, b2 []byte diff --git a/cmd/gomarkdoc/output.go b/cmd/gomarkdoc/output.go index aae674f..e27e0b9 100644 --- a/cmd/gomarkdoc/output.go +++ b/cmd/gomarkdoc/output.go @@ -8,10 +8,13 @@ import ( "os" "path/filepath" "regexp" + "time" "github.com/Weborama/gomarkdoc" "github.com/Weborama/gomarkdoc/lang" "github.com/Weborama/gomarkdoc/logger" + "github.com/princjef/termdiff" + "github.com/sergi/go-diff/diffmatchpatch" ) func writeOutput(specs []*PackageSpec, opts commandOptions) error { @@ -47,6 +50,7 @@ func writeOutput(specs []*PackageSpec, opts commandOptions) error { filePkgs[spec.outputFile] = append(filePkgs[spec.outputFile], spec.pkg) } + var checkErr error for fileName, pkgs := range filePkgs { file := lang.NewFile(header, footer, pkgs) @@ -55,29 +59,41 @@ func writeOutput(specs []*PackageSpec, opts commandOptions) error { return err } - if opts.embed && fileName != "" { - text = embedContents(log, fileName, text) + checkErr, err = handleFile(log, fileName, text, opts) + if err != nil { + return err } + } - switch { - case fileName == "": - fmt.Fprint(os.Stdout, text) - case opts.check: - var b bytes.Buffer - fmt.Fprint(&b, text) - if err := checkFile(&b, fileName); err != nil { - return err - } - default: - if err := writeFile(fileName, text); err != nil { - return fmt.Errorf("failed to write output file %s: %w", fileName, err) - } - } + if checkErr != nil { + return checkErr } return nil } +func handleFile(log logger.Logger, fileName string, text string, opts commandOptions) (error, error) { + if opts.embed && fileName != "" { + text = embedContents(log, fileName, text) + } + + switch { + case fileName == "": + fmt.Fprint(os.Stdout, text) + case opts.check: + var b bytes.Buffer + fmt.Fprint(&b, text) + if err := checkFile(&b, fileName); err != nil { + return err, nil + } + default: + if err := writeFile(fileName, text); err != nil { + return nil, fmt.Errorf("failed to write output file %s: %w", fileName, err) + } + } + return nil, nil +} + func writeFile(fileName string, text string) error { folder := filepath.Dir(fileName) @@ -97,23 +113,36 @@ func writeFile(fileName string, text string) error { func checkFile(b *bytes.Buffer, path string) error { checkErr := errors.New("output does not match current files. Did you forget to run gomarkdoc?") - f, err := os.Open(path) - if err != nil { - if err == os.ErrNotExist { - return checkErr - } - + fileContents, err := os.ReadFile(path) + if err == os.ErrNotExist { + fileContents = []byte{} + } else if err != nil { return fmt.Errorf("failed to open file %s for checking: %w", path, err) } - defer f.Close() + differ := diffmatchpatch.New() + diff := differ.DiffBisect(b.String(), string(fileContents), time.Now().Add(time.Second)) - match, err := compare(b, f) - if err != nil { - return fmt.Errorf("failure while attempting to check contents of %s: %w", path, err) + // Remove equal diffs + filtered := make([]diffmatchpatch.Diff, 0, len(diff)) + for _, d := range diff { + if d.Type == diffmatchpatch.DiffEqual { + continue + } + + filtered = append(filtered, d) } - if !match { + if len(filtered) != 0 { + diffs := termdiff.DiffsFromDiffMatchPatch(diff) + fmt.Fprintln(os.Stderr) + termdiff.Fprint( + os.Stderr, + path, + diffs, + termdiff.WithBeforeText("(expected)"), + termdiff.WithAfterText("(actual)"), + ) return checkErr } diff --git a/doc.go b/doc.go index 8d9e6b3..e8a07e8 100644 --- a/doc.go +++ b/doc.go @@ -28,6 +28,7 @@ // -c, --check Check the output to see if it matches the generated documentation. --output must be specified to use this. // --config string File from which to load configuration (default: .gomarkdoc.yml) // -e, --embed Embed documentation into existing markdown files if available, otherwise append to file. +// --exclude-dirs strings List of package directories to ignore when producing documentation. // --footer string Additional content to inject at the end of each output file. // --footer-file string File containing additional content to inject at the end of each output file. // -f, --format string Format to use for writing output data. Valid options: github (default), azure-devops, plain (default "github") @@ -61,6 +62,18 @@ // local and remote packages in the same command invocation as separate // arguments. // +// If you have a project with many packages but you want to skip documentation +// generation for some, you can use the --exclude-dirs option. This will remove +// any matching directories from the list of directories to process. Excluded +// directories are specified using the same pathing syntax as the packages to +// process. Multiple expressions may be comma-separated or specified by using +// the --exclude-dirs flag multiple times. +// +// For example, in this repository we generate documentation for the entire +// project while excluding our test packages by running: +// +// gomarkdoc --exclude-dirs ./testData/... ./... +// // # Output Redirection // // By default, the documentation generated by the gomarkdoc command is sent to @@ -127,11 +140,11 @@ // // - import: generates the import code used to pull in a package. // -// Overriding with the -t option uses a key-vaule pair mapping a template name -// to the file containing the contents of the override template to use. -// Specified template files must exist: +// Overriding with the --template-file option uses a key-value pair mapping a +// template name to the file containing the contents of the override template to +// use. Specified template files must exist: // -// gomarkdoc -t package=custom-package.gotxt -t doc=custom-doc.gotxt . +// gomarkdoc --template-file package=custom-package.gotxt --template-file doc=custom-doc.gotxt . // // # Additional Options // diff --git a/format/README.md b/format/README.md index d216aae..6b44224 100755 --- a/format/README.md +++ b/format/README.md @@ -12,51 +12,61 @@ Each of the formats in this package contains the same set of formatting function ## Index -- [type AzureDevOpsMarkdown](<#type-azuredevopsmarkdown>) - - [func (f *AzureDevOpsMarkdown) Accordion(title, body string) (string, error)](<#func-azuredevopsmarkdown-accordion>) - - [func (f *AzureDevOpsMarkdown) AccordionHeader(title string) (string, error)](<#func-azuredevopsmarkdown-accordionheader>) - - [func (f *AzureDevOpsMarkdown) AccordionTerminator() (string, error)](<#func-azuredevopsmarkdown-accordionterminator>) - - [func (f *AzureDevOpsMarkdown) Bold(text string) (string, error)](<#func-azuredevopsmarkdown-bold>) - - [func (f *AzureDevOpsMarkdown) CodeBlock(language, code string) (string, error)](<#func-azuredevopsmarkdown-codeblock>) - - [func (f *AzureDevOpsMarkdown) CodeHref(loc lang.Location) (string, error)](<#func-azuredevopsmarkdown-codehref>) - - [func (f *AzureDevOpsMarkdown) Escape(text string) string](<#func-azuredevopsmarkdown-escape>) - - [func (f *AzureDevOpsMarkdown) Header(level int, text string) (string, error)](<#func-azuredevopsmarkdown-header>) - - [func (f *AzureDevOpsMarkdown) Link(text, href string) (string, error)](<#func-azuredevopsmarkdown-link>) - - [func (f *AzureDevOpsMarkdown) ListEntry(depth int, text string) (string, error)](<#func-azuredevopsmarkdown-listentry>) - - [func (f *AzureDevOpsMarkdown) LocalHref(headerText string) (string, error)](<#func-azuredevopsmarkdown-localhref>) - - [func (f *AzureDevOpsMarkdown) Paragraph(text string) (string, error)](<#func-azuredevopsmarkdown-paragraph>) - - [func (f *AzureDevOpsMarkdown) RawHeader(level int, text string) (string, error)](<#func-azuredevopsmarkdown-rawheader>) -- [type Format](<#type-format>) -- [type GitHubFlavoredMarkdown](<#type-githubflavoredmarkdown>) - - [func (f *GitHubFlavoredMarkdown) Accordion(title, body string) (string, error)](<#func-githubflavoredmarkdown-accordion>) - - [func (f *GitHubFlavoredMarkdown) AccordionHeader(title string) (string, error)](<#func-githubflavoredmarkdown-accordionheader>) - - [func (f *GitHubFlavoredMarkdown) AccordionTerminator() (string, error)](<#func-githubflavoredmarkdown-accordionterminator>) - - [func (f *GitHubFlavoredMarkdown) Bold(text string) (string, error)](<#func-githubflavoredmarkdown-bold>) - - [func (f *GitHubFlavoredMarkdown) CodeBlock(language, code string) (string, error)](<#func-githubflavoredmarkdown-codeblock>) - - [func (f *GitHubFlavoredMarkdown) CodeHref(loc lang.Location) (string, error)](<#func-githubflavoredmarkdown-codehref>) - - [func (f *GitHubFlavoredMarkdown) Escape(text string) string](<#func-githubflavoredmarkdown-escape>) - - [func (f *GitHubFlavoredMarkdown) Header(level int, text string) (string, error)](<#func-githubflavoredmarkdown-header>) - - [func (f *GitHubFlavoredMarkdown) Link(text, href string) (string, error)](<#func-githubflavoredmarkdown-link>) - - [func (f *GitHubFlavoredMarkdown) ListEntry(depth int, text string) (string, error)](<#func-githubflavoredmarkdown-listentry>) - - [func (f *GitHubFlavoredMarkdown) LocalHref(headerText string) (string, error)](<#func-githubflavoredmarkdown-localhref>) - - [func (f *GitHubFlavoredMarkdown) Paragraph(text string) (string, error)](<#func-githubflavoredmarkdown-paragraph>) - - [func (f *GitHubFlavoredMarkdown) RawHeader(level int, text string) (string, error)](<#func-githubflavoredmarkdown-rawheader>) -- [type PlainMarkdown](<#type-plainmarkdown>) - - [func (f *PlainMarkdown) Accordion(title, body string) (string, error)](<#func-plainmarkdown-accordion>) - - [func (f *PlainMarkdown) AccordionHeader(title string) (string, error)](<#func-plainmarkdown-accordionheader>) - - [func (f *PlainMarkdown) AccordionTerminator() (string, error)](<#func-plainmarkdown-accordionterminator>) - - [func (f *PlainMarkdown) Bold(text string) (string, error)](<#func-plainmarkdown-bold>) - - [func (f *PlainMarkdown) CodeBlock(language, code string) (string, error)](<#func-plainmarkdown-codeblock>) - - [func (f *PlainMarkdown) CodeHref(loc lang.Location) (string, error)](<#func-plainmarkdown-codehref>) - - [func (f *PlainMarkdown) Escape(text string) string](<#func-plainmarkdown-escape>) - - [func (f *PlainMarkdown) Header(level int, text string) (string, error)](<#func-plainmarkdown-header>) - - [func (f *PlainMarkdown) Link(text, href string) (string, error)](<#func-plainmarkdown-link>) - - [func (f *PlainMarkdown) ListEntry(depth int, text string) (string, error)](<#func-plainmarkdown-listentry>) - - [func (f *PlainMarkdown) LocalHref(headerText string) (string, error)](<#func-plainmarkdown-localhref>) - - [func (f *PlainMarkdown) Paragraph(text string) (string, error)](<#func-plainmarkdown-paragraph>) - - [func (f *PlainMarkdown) RawHeader(level int, text string) (string, error)](<#func-plainmarkdown-rawheader>) - - +- [type AzureDevOpsMarkdown](<#AzureDevOpsMarkdown>) + - [func \(f \*AzureDevOpsMarkdown\) Accordion\(title, body string\) \(string, error\)](<#AzureDevOpsMarkdown.Accordion>) + - [func \(f \*AzureDevOpsMarkdown\) AccordionHeader\(title string\) \(string, error\)](<#AzureDevOpsMarkdown.AccordionHeader>) + - [func \(f \*AzureDevOpsMarkdown\) AccordionTerminator\(\) \(string, error\)](<#AzureDevOpsMarkdown.AccordionTerminator>) + - [func \(f \*AzureDevOpsMarkdown\) Anchor\(anchor string\) string](<#AzureDevOpsMarkdown.Anchor>) + - [func \(f \*AzureDevOpsMarkdown\) AnchorHeader\(level int, text, anchor string\) \(string, error\)](<#AzureDevOpsMarkdown.AnchorHeader>) + - [func \(f \*AzureDevOpsMarkdown\) Bold\(text string\) \(string, error\)](<#AzureDevOpsMarkdown.Bold>) + - [func \(f \*AzureDevOpsMarkdown\) CodeBlock\(language, code string\) \(string, error\)](<#AzureDevOpsMarkdown.CodeBlock>) + - [func \(f \*AzureDevOpsMarkdown\) CodeHref\(loc lang.Location\) \(string, error\)](<#AzureDevOpsMarkdown.CodeHref>) + - [func \(f \*AzureDevOpsMarkdown\) Escape\(text string\) string](<#AzureDevOpsMarkdown.Escape>) + - [func \(f \*AzureDevOpsMarkdown\) Header\(level int, text string\) \(string, error\)](<#AzureDevOpsMarkdown.Header>) + - [func \(f \*AzureDevOpsMarkdown\) Link\(text, href string\) \(string, error\)](<#AzureDevOpsMarkdown.Link>) + - [func \(f \*AzureDevOpsMarkdown\) ListEntry\(depth int, text string\) \(string, error\)](<#AzureDevOpsMarkdown.ListEntry>) + - [func \(f \*AzureDevOpsMarkdown\) LocalHref\(headerText string\) \(string, error\)](<#AzureDevOpsMarkdown.LocalHref>) + - [func \(f \*AzureDevOpsMarkdown\) RawAnchorHeader\(level int, text, anchor string\) \(string, error\)](<#AzureDevOpsMarkdown.RawAnchorHeader>) + - [func \(f \*AzureDevOpsMarkdown\) RawHeader\(level int, text string\) \(string, error\)](<#AzureDevOpsMarkdown.RawHeader>) + - [func \(f \*AzureDevOpsMarkdown\) RawLocalHref\(anchor string\) string](<#AzureDevOpsMarkdown.RawLocalHref>) +- [type Format](<#Format>) +- [type GitHubFlavoredMarkdown](<#GitHubFlavoredMarkdown>) + - [func \(f \*GitHubFlavoredMarkdown\) Accordion\(title, body string\) \(string, error\)](<#GitHubFlavoredMarkdown.Accordion>) + - [func \(f \*GitHubFlavoredMarkdown\) AccordionHeader\(title string\) \(string, error\)](<#GitHubFlavoredMarkdown.AccordionHeader>) + - [func \(f \*GitHubFlavoredMarkdown\) AccordionTerminator\(\) \(string, error\)](<#GitHubFlavoredMarkdown.AccordionTerminator>) + - [func \(f \*GitHubFlavoredMarkdown\) Anchor\(anchor string\) string](<#GitHubFlavoredMarkdown.Anchor>) + - [func \(f \*GitHubFlavoredMarkdown\) AnchorHeader\(level int, text, anchor string\) \(string, error\)](<#GitHubFlavoredMarkdown.AnchorHeader>) + - [func \(f \*GitHubFlavoredMarkdown\) Bold\(text string\) \(string, error\)](<#GitHubFlavoredMarkdown.Bold>) + - [func \(f \*GitHubFlavoredMarkdown\) CodeBlock\(language, code string\) \(string, error\)](<#GitHubFlavoredMarkdown.CodeBlock>) + - [func \(f \*GitHubFlavoredMarkdown\) CodeHref\(loc lang.Location\) \(string, error\)](<#GitHubFlavoredMarkdown.CodeHref>) + - [func \(f \*GitHubFlavoredMarkdown\) Escape\(text string\) string](<#GitHubFlavoredMarkdown.Escape>) + - [func \(f \*GitHubFlavoredMarkdown\) Header\(level int, text string\) \(string, error\)](<#GitHubFlavoredMarkdown.Header>) + - [func \(f \*GitHubFlavoredMarkdown\) Link\(text, href string\) \(string, error\)](<#GitHubFlavoredMarkdown.Link>) + - [func \(f \*GitHubFlavoredMarkdown\) ListEntry\(depth int, text string\) \(string, error\)](<#GitHubFlavoredMarkdown.ListEntry>) + - [func \(f \*GitHubFlavoredMarkdown\) LocalHref\(headerText string\) \(string, error\)](<#GitHubFlavoredMarkdown.LocalHref>) + - [func \(f \*GitHubFlavoredMarkdown\) RawAnchorHeader\(level int, text, anchor string\) \(string, error\)](<#GitHubFlavoredMarkdown.RawAnchorHeader>) + - [func \(f \*GitHubFlavoredMarkdown\) RawHeader\(level int, text string\) \(string, error\)](<#GitHubFlavoredMarkdown.RawHeader>) + - [func \(f \*GitHubFlavoredMarkdown\) RawLocalHref\(anchor string\) string](<#GitHubFlavoredMarkdown.RawLocalHref>) +- [type PlainMarkdown](<#PlainMarkdown>) + - [func \(f \*PlainMarkdown\) Accordion\(title, body string\) \(string, error\)](<#PlainMarkdown.Accordion>) + - [func \(f \*PlainMarkdown\) AccordionHeader\(title string\) \(string, error\)](<#PlainMarkdown.AccordionHeader>) + - [func \(f \*PlainMarkdown\) AccordionTerminator\(\) \(string, error\)](<#PlainMarkdown.AccordionTerminator>) + - [func \(f \*PlainMarkdown\) Anchor\(anchor string\) string](<#PlainMarkdown.Anchor>) + - [func \(f \*PlainMarkdown\) AnchorHeader\(level int, text, anchor string\) \(string, error\)](<#PlainMarkdown.AnchorHeader>) + - [func \(f \*PlainMarkdown\) Bold\(text string\) \(string, error\)](<#PlainMarkdown.Bold>) + - [func \(f \*PlainMarkdown\) CodeBlock\(language, code string\) \(string, error\)](<#PlainMarkdown.CodeBlock>) + - [func \(f \*PlainMarkdown\) CodeHref\(loc lang.Location\) \(string, error\)](<#PlainMarkdown.CodeHref>) + - [func \(f \*PlainMarkdown\) Escape\(text string\) string](<#PlainMarkdown.Escape>) + - [func \(f \*PlainMarkdown\) Header\(level int, text string\) \(string, error\)](<#PlainMarkdown.Header>) + - [func \(f \*PlainMarkdown\) Link\(text, href string\) \(string, error\)](<#PlainMarkdown.Link>) + - [func \(f \*PlainMarkdown\) ListEntry\(depth int, text string\) \(string, error\)](<#PlainMarkdown.ListEntry>) + - [func \(f \*PlainMarkdown\) LocalHref\(headerText string\) \(string, error\)](<#PlainMarkdown.LocalHref>) + - [func \(f \*PlainMarkdown\) RawAnchorHeader\(level int, text, anchor string\) \(string, error\)](<#PlainMarkdown.RawAnchorHeader>) + - [func \(f \*PlainMarkdown\) RawHeader\(level int, text string\) \(string, error\)](<#PlainMarkdown.RawHeader>) + - [func \(f \*PlainMarkdown\) RawLocalHref\(anchor string\) string](<#PlainMarkdown.RawLocalHref>) + + + ## type [AzureDevOpsMarkdown]() AzureDevOpsMarkdown provides a Format which is compatible with Azure DevOps's syntax and semantics. See the Azure DevOps documentation for more details about their markdown format: https://docs.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops @@ -65,7 +75,8 @@ AzureDevOpsMarkdown provides a Format which is compatible with Azure DevOps's sy type AzureDevOpsMarkdown struct{} ``` -### func \(\*AzureDevOpsMarkdown\) [Accordion]() + +### func \(\*AzureDevOpsMarkdown\) [Accordion]() ```go func (f *AzureDevOpsMarkdown) Accordion(title, body string) (string, error) @@ -73,7 +84,8 @@ func (f *AzureDevOpsMarkdown) Accordion(title, body string) (string, error) Accordion generates a collapsible content. The accordion's visible title while collapsed is the provided title and the expanded content is the body. -### func \(\*AzureDevOpsMarkdown\) [AccordionHeader]() + +### func \(\*AzureDevOpsMarkdown\) [AccordionHeader]() ```go func (f *AzureDevOpsMarkdown) AccordionHeader(title string) (string, error) @@ -87,7 +99,8 @@ The AccordionHeader is expected to be used in conjunction with AccordionTerminat accordion := format.AccordionHeader("Accordion Title") + "Accordion Body" + format.AccordionTerminator() ``` -### func \(\*AzureDevOpsMarkdown\) [AccordionTerminator]() + +### func \(\*AzureDevOpsMarkdown\) [AccordionTerminator]() ```go func (f *AzureDevOpsMarkdown) AccordionTerminator() (string, error) @@ -95,6 +108,25 @@ func (f *AzureDevOpsMarkdown) AccordionTerminator() (string, error) AccordionTerminator generates the code necessary to terminate an accordion after the body. It is expected to be used in conjunction with AccordionHeader\(\). See AccordionHeader for a full description. + +### func \(\*AzureDevOpsMarkdown\) [Anchor]() + +```go +func (f *AzureDevOpsMarkdown) Anchor(anchor string) string +``` + +Anchor produces an anchor for the provided link. + + +### func \(\*AzureDevOpsMarkdown\) [AnchorHeader]() + +```go +func (f *AzureDevOpsMarkdown) AnchorHeader(level int, text, anchor string) (string, error) +``` + +AnchorHeader converts the provided text and custom anchor link into a header of the provided level. The level is expected to be at least 1. + + ### func \(\*AzureDevOpsMarkdown\) [Bold]() ```go @@ -103,6 +135,7 @@ func (f *AzureDevOpsMarkdown) Bold(text string) (string, error) Bold converts the provided text to bold + ### func \(\*AzureDevOpsMarkdown\) [CodeBlock]() ```go @@ -111,7 +144,8 @@ func (f *AzureDevOpsMarkdown) CodeBlock(language, code string) (string, error) CodeBlock wraps the provided code as a code block and tags it with the provided language \(or no language if the empty string is provided\). -### func \(\*AzureDevOpsMarkdown\) [CodeHref]() + +### func \(\*AzureDevOpsMarkdown\) [CodeHref]() ```go func (f *AzureDevOpsMarkdown) CodeHref(loc lang.Location) (string, error) @@ -119,7 +153,8 @@ func (f *AzureDevOpsMarkdown) CodeHref(loc lang.Location) (string, error) CodeHref generates an href to the provided code entry. -### func \(\*AzureDevOpsMarkdown\) [Escape]() + +### func \(\*AzureDevOpsMarkdown\) [Escape]() ```go func (f *AzureDevOpsMarkdown) Escape(text string) string @@ -127,7 +162,8 @@ func (f *AzureDevOpsMarkdown) Escape(text string) string Escape escapes special markdown characters from the provided text. -### func \(\*AzureDevOpsMarkdown\) [Header]() + +### func \(\*AzureDevOpsMarkdown\) [Header]() ```go func (f *AzureDevOpsMarkdown) Header(level int, text string) (string, error) @@ -135,7 +171,8 @@ func (f *AzureDevOpsMarkdown) Header(level int, text string) (string, error) Header converts the provided text into a header of the provided level. The level is expected to be at least 1. -### func \(\*AzureDevOpsMarkdown\) [Link]() + +### func \(\*AzureDevOpsMarkdown\) [Link]() ```go func (f *AzureDevOpsMarkdown) Link(text, href string) (string, error) @@ -143,7 +180,8 @@ func (f *AzureDevOpsMarkdown) Link(text, href string) (string, error) Link generates a link with the given text and href values. -### func \(\*AzureDevOpsMarkdown\) [ListEntry]() + +### func \(\*AzureDevOpsMarkdown\) [ListEntry]() ```go func (f *AzureDevOpsMarkdown) ListEntry(depth int, text string) (string, error) @@ -151,7 +189,8 @@ func (f *AzureDevOpsMarkdown) ListEntry(depth int, text string) (string, error) ListEntry generates an unordered list entry with the provided text at the provided zero\-indexed depth. A depth of 0 is considered the topmost level of list. -### func \(\*AzureDevOpsMarkdown\) [LocalHref]() + +### func \(\*AzureDevOpsMarkdown\) [LocalHref]() ```go func (f *AzureDevOpsMarkdown) LocalHref(headerText string) (string, error) @@ -159,15 +198,17 @@ func (f *AzureDevOpsMarkdown) LocalHref(headerText string) (string, error) LocalHref generates an href for navigating to a header with the given headerText located within the same document as the href itself. Link generation follows the guidelines here: https://docs.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#anchor-links -### func \(\*AzureDevOpsMarkdown\) [Paragraph]() + +### func \(\*AzureDevOpsMarkdown\) [RawAnchorHeader]() ```go -func (f *AzureDevOpsMarkdown) Paragraph(text string) (string, error) +func (f *AzureDevOpsMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) ``` -Paragraph formats a paragraph with the provided text as the contents. +RawAnchorHeader converts the provided text and custom anchor link into a header of the provided level without escaping the header text. The level is expected to be at least 1. -### func \(\*AzureDevOpsMarkdown\) [RawHeader]() + +### func \(\*AzureDevOpsMarkdown\) [RawHeader]() ```go func (f *AzureDevOpsMarkdown) RawHeader(level int, text string) (string, error) @@ -175,7 +216,17 @@ func (f *AzureDevOpsMarkdown) RawHeader(level int, text string) (string, error) RawHeader converts the provided text into a header of the provided level without escaping the header text. The level is expected to be at least 1. -## type [Format]() + +### func \(\*AzureDevOpsMarkdown\) [RawLocalHref]() + +```go +func (f *AzureDevOpsMarkdown) RawLocalHref(anchor string) string +``` + +RawLocalHref generates an href within the same document but with a direct link provided instead of text to slugify. + + +## type [Format]() Format is a generic interface for formatting documentation contents in a particular way. @@ -188,10 +239,22 @@ type Format interface { // provided language (or no language if the empty string is provided). CodeBlock(language, code string) (string, error) + // Anchor produces an anchor for the provided link. + Anchor(anchor string) string + + // AnchorHeader converts the provided text and custom anchor link into a + // header of the provided level. The level is expected to be at least 1. + AnchorHeader(level int, text, anchor string) (string, error) + // Header converts the provided text into a header of the provided level. // The level is expected to be at least 1. Header(level int, text string) (string, error) + // RawAnchorHeader converts the provided text and custom anchor link into a + // header of the provided level without escaping the header text. The level + // is expected to be at least 1. + RawAnchorHeader(level int, text, anchor string) (string, error) + // RawHeader converts the provided text into a header of the provided level // without escaping the header text. The level is expected to be at least 1. RawHeader(level int, text string) (string, error) @@ -200,6 +263,10 @@ type Format interface { // headerText located within the same document as the href itself. LocalHref(headerText string) (string, error) + // RawLocalHref generates an href within the same document but with a direct + // link provided instead of text to slugify. + RawLocalHref(anchor string) string + // Link generates a link with the given text and href values. Link(text, href string) (string, error) @@ -232,14 +299,12 @@ type Format interface { // AccordionHeader(). See AccordionHeader for a full description. AccordionTerminator() (string, error) - // Paragraph formats a paragraph with the provided text as the contents. - Paragraph(text string) (string, error) - // Escape escapes special markdown characters from the provided text. Escape(text string) string } ``` + ## type [GitHubFlavoredMarkdown]() GitHubFlavoredMarkdown provides a Format which is compatible with GitHub Flavored Markdown's syntax and semantics. See GitHub's documentation for more details about their markdown format: https://guides.github.com/features/mastering-markdown/ @@ -248,7 +313,8 @@ GitHubFlavoredMarkdown provides a Format which is compatible with GitHub Flavore type GitHubFlavoredMarkdown struct{} ``` -### func \(\*GitHubFlavoredMarkdown\) [Accordion]() + +### func \(\*GitHubFlavoredMarkdown\) [Accordion]() ```go func (f *GitHubFlavoredMarkdown) Accordion(title, body string) (string, error) @@ -256,7 +322,8 @@ func (f *GitHubFlavoredMarkdown) Accordion(title, body string) (string, error) Accordion generates a collapsible content. The accordion's visible title while collapsed is the provided title and the expanded content is the body. -### func \(\*GitHubFlavoredMarkdown\) [AccordionHeader]() + +### func \(\*GitHubFlavoredMarkdown\) [AccordionHeader]() ```go func (f *GitHubFlavoredMarkdown) AccordionHeader(title string) (string, error) @@ -270,7 +337,8 @@ The AccordionHeader is expected to be used in conjunction with AccordionTerminat accordion := format.AccordionHeader("Accordion Title") + "Accordion Body" + format.AccordionTerminator() ``` -### func \(\*GitHubFlavoredMarkdown\) [AccordionTerminator]() + +### func \(\*GitHubFlavoredMarkdown\) [AccordionTerminator]() ```go func (f *GitHubFlavoredMarkdown) AccordionTerminator() (string, error) @@ -278,6 +346,25 @@ func (f *GitHubFlavoredMarkdown) AccordionTerminator() (string, error) AccordionTerminator generates the code necessary to terminate an accordion after the body. It is expected to be used in conjunction with AccordionHeader\(\). See AccordionHeader for a full description. + +### func \(\*GitHubFlavoredMarkdown\) [Anchor]() + +```go +func (f *GitHubFlavoredMarkdown) Anchor(anchor string) string +``` + +Anchor produces an anchor for the provided link. + + +### func \(\*GitHubFlavoredMarkdown\) [AnchorHeader]() + +```go +func (f *GitHubFlavoredMarkdown) AnchorHeader(level int, text, anchor string) (string, error) +``` + +AnchorHeader converts the provided text and custom anchor link into a header of the provided level. The level is expected to be at least 1. + + ### func \(\*GitHubFlavoredMarkdown\) [Bold]() ```go @@ -286,6 +373,7 @@ func (f *GitHubFlavoredMarkdown) Bold(text string) (string, error) Bold converts the provided text to bold + ### func \(\*GitHubFlavoredMarkdown\) [CodeBlock]() ```go @@ -294,7 +382,8 @@ func (f *GitHubFlavoredMarkdown) CodeBlock(language, code string) (string, error CodeBlock wraps the provided code as a code block and tags it with the provided language \(or no language if the empty string is provided\). -### func \(\*GitHubFlavoredMarkdown\) [CodeHref]() + +### func \(\*GitHubFlavoredMarkdown\) [CodeHref]() ```go func (f *GitHubFlavoredMarkdown) CodeHref(loc lang.Location) (string, error) @@ -302,7 +391,8 @@ func (f *GitHubFlavoredMarkdown) CodeHref(loc lang.Location) (string, error) CodeHref generates an href to the provided code entry. -### func \(\*GitHubFlavoredMarkdown\) [Escape]() + +### func \(\*GitHubFlavoredMarkdown\) [Escape]() ```go func (f *GitHubFlavoredMarkdown) Escape(text string) string @@ -310,7 +400,8 @@ func (f *GitHubFlavoredMarkdown) Escape(text string) string Escape escapes special markdown characters from the provided text. -### func \(\*GitHubFlavoredMarkdown\) [Header]() + +### func \(\*GitHubFlavoredMarkdown\) [Header]() ```go func (f *GitHubFlavoredMarkdown) Header(level int, text string) (string, error) @@ -318,7 +409,8 @@ func (f *GitHubFlavoredMarkdown) Header(level int, text string) (string, error) Header converts the provided text into a header of the provided level. The level is expected to be at least 1. -### func \(\*GitHubFlavoredMarkdown\) [Link]() + +### func \(\*GitHubFlavoredMarkdown\) [Link]() ```go func (f *GitHubFlavoredMarkdown) Link(text, href string) (string, error) @@ -326,7 +418,8 @@ func (f *GitHubFlavoredMarkdown) Link(text, href string) (string, error) Link generates a link with the given text and href values. -### func \(\*GitHubFlavoredMarkdown\) [ListEntry]() + +### func \(\*GitHubFlavoredMarkdown\) [ListEntry]() ```go func (f *GitHubFlavoredMarkdown) ListEntry(depth int, text string) (string, error) @@ -334,7 +427,8 @@ func (f *GitHubFlavoredMarkdown) ListEntry(depth int, text string) (string, erro ListEntry generates an unordered list entry with the provided text at the provided zero\-indexed depth. A depth of 0 is considered the topmost level of list. -### func \(\*GitHubFlavoredMarkdown\) [LocalHref]() + +### func \(\*GitHubFlavoredMarkdown\) [LocalHref]() ```go func (f *GitHubFlavoredMarkdown) LocalHref(headerText string) (string, error) @@ -342,15 +436,17 @@ func (f *GitHubFlavoredMarkdown) LocalHref(headerText string) (string, error) LocalHref generates an href for navigating to a header with the given headerText located within the same document as the href itself. -### func \(\*GitHubFlavoredMarkdown\) [Paragraph]() + +### func \(\*GitHubFlavoredMarkdown\) [RawAnchorHeader]() ```go -func (f *GitHubFlavoredMarkdown) Paragraph(text string) (string, error) +func (f *GitHubFlavoredMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) ``` -Paragraph formats a paragraph with the provided text as the contents. +RawAnchorHeader converts the provided text and custom anchor link into a header of the provided level without escaping the header text. The level is expected to be at least 1. -### func \(\*GitHubFlavoredMarkdown\) [RawHeader]() + +### func \(\*GitHubFlavoredMarkdown\) [RawHeader]() ```go func (f *GitHubFlavoredMarkdown) RawHeader(level int, text string) (string, error) @@ -358,6 +454,16 @@ func (f *GitHubFlavoredMarkdown) RawHeader(level int, text string) (string, erro RawHeader converts the provided text into a header of the provided level without escaping the header text. The level is expected to be at least 1. + +### func \(\*GitHubFlavoredMarkdown\) [RawLocalHref]() + +```go +func (f *GitHubFlavoredMarkdown) RawLocalHref(anchor string) string +``` + +RawLocalHref generates an href within the same document but with a direct link provided instead of text to slugify. + + ## type [PlainMarkdown]() PlainMarkdown provides a Format which is compatible with the base Markdown format specification. @@ -366,7 +472,8 @@ PlainMarkdown provides a Format which is compatible with the base Markdown forma type PlainMarkdown struct{} ``` -### func \(\*PlainMarkdown\) [Accordion]() + +### func \(\*PlainMarkdown\) [Accordion]() ```go func (f *PlainMarkdown) Accordion(title, body string) (string, error) @@ -374,7 +481,8 @@ func (f *PlainMarkdown) Accordion(title, body string) (string, error) Accordion generates a collapsible content. Since accordions are not supported by plain markdown, this generates a level 6 header followed by a paragraph. -### func \(\*PlainMarkdown\) [AccordionHeader]() + +### func \(\*PlainMarkdown\) [AccordionHeader]() ```go func (f *PlainMarkdown) AccordionHeader(title string) (string, error) @@ -388,7 +496,8 @@ The AccordionHeader is expected to be used in conjunction with AccordionTerminat accordion := format.AccordionHeader("Accordion Title") + "Accordion Body" + format.AccordionTerminator() ``` -### func \(\*PlainMarkdown\) [AccordionTerminator]() + +### func \(\*PlainMarkdown\) [AccordionTerminator]() ```go func (f *PlainMarkdown) AccordionTerminator() (string, error) @@ -396,6 +505,25 @@ func (f *PlainMarkdown) AccordionTerminator() (string, error) AccordionTerminator generates the code necessary to terminate an accordion after the body. Since accordions are not supported in plain markdown, this completes a paragraph section. It is expected to be used in conjunction with AccordionHeader\(\). See AccordionHeader for a full description. + +### func \(\*PlainMarkdown\) [Anchor]() + +```go +func (f *PlainMarkdown) Anchor(anchor string) string +``` + +Anchor produces an anchor for the provided link. + + +### func \(\*PlainMarkdown\) [AnchorHeader]() + +```go +func (f *PlainMarkdown) AnchorHeader(level int, text, anchor string) (string, error) +``` + +AnchorHeader converts the provided text and custom anchor link into a header of the provided level. The level is expected to be at least 1. + + ### func \(\*PlainMarkdown\) [Bold]() ```go @@ -404,6 +532,7 @@ func (f *PlainMarkdown) Bold(text string) (string, error) Bold converts the provided text to bold + ### func \(\*PlainMarkdown\) [CodeBlock]() ```go @@ -412,7 +541,8 @@ func (f *PlainMarkdown) CodeBlock(language, code string) (string, error) CodeBlock wraps the provided code as a code block. The provided language is ignored as it is not supported in plain markdown. -### func \(\*PlainMarkdown\) [CodeHref]() + +### func \(\*PlainMarkdown\) [CodeHref]() ```go func (f *PlainMarkdown) CodeHref(loc lang.Location) (string, error) @@ -420,7 +550,8 @@ func (f *PlainMarkdown) CodeHref(loc lang.Location) (string, error) CodeHref always returns the empty string, as there is no defined file linking format in standard markdown. -### func \(\*PlainMarkdown\) [Escape]() + +### func \(\*PlainMarkdown\) [Escape]() ```go func (f *PlainMarkdown) Escape(text string) string @@ -428,7 +559,8 @@ func (f *PlainMarkdown) Escape(text string) string Escape escapes special markdown characters from the provided text. -### func \(\*PlainMarkdown\) [Header]() + +### func \(\*PlainMarkdown\) [Header]() ```go func (f *PlainMarkdown) Header(level int, text string) (string, error) @@ -436,7 +568,8 @@ func (f *PlainMarkdown) Header(level int, text string) (string, error) Header converts the provided text into a header of the provided level. The level is expected to be at least 1. -### func \(\*PlainMarkdown\) [Link]() + +### func \(\*PlainMarkdown\) [Link]() ```go func (f *PlainMarkdown) Link(text, href string) (string, error) @@ -444,7 +577,8 @@ func (f *PlainMarkdown) Link(text, href string) (string, error) Link generates a link with the given text and href values. -### func \(\*PlainMarkdown\) [ListEntry]() + +### func \(\*PlainMarkdown\) [ListEntry]() ```go func (f *PlainMarkdown) ListEntry(depth int, text string) (string, error) @@ -452,7 +586,8 @@ func (f *PlainMarkdown) ListEntry(depth int, text string) (string, error) ListEntry generates an unordered list entry with the provided text at the provided zero\-indexed depth. A depth of 0 is considered the topmost level of list. -### func \(\*PlainMarkdown\) [LocalHref]() + +### func \(\*PlainMarkdown\) [LocalHref]() ```go func (f *PlainMarkdown) LocalHref(headerText string) (string, error) @@ -460,15 +595,17 @@ func (f *PlainMarkdown) LocalHref(headerText string) (string, error) LocalHref always returns the empty string, as header links are not supported in plain markdown. -### func \(\*PlainMarkdown\) [Paragraph]() + +### func \(\*PlainMarkdown\) [RawAnchorHeader]() ```go -func (f *PlainMarkdown) Paragraph(text string) (string, error) +func (f *PlainMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) ``` -Paragraph formats a paragraph with the provided text as the contents. +RawAnchorHeader converts the provided text and custom anchor link into a header of the provided level without escaping the header text. The level is expected to be at least 1. -### func \(\*PlainMarkdown\) [RawHeader]() + +### func \(\*PlainMarkdown\) [RawHeader]() ```go func (f *PlainMarkdown) RawHeader(level int, text string) (string, error) @@ -476,6 +613,13 @@ func (f *PlainMarkdown) RawHeader(level int, text string) (string, error) RawHeader converts the provided text into a header of the provided level without escaping the header text. The level is expected to be at least 1. + +### func \(\*PlainMarkdown\) [RawLocalHref]() + +```go +func (f *PlainMarkdown) RawLocalHref(anchor string) string +``` +RawLocalHref generates an href within the same document but with a direct link provided instead of text to slugify. Generated by [gomarkdoc]() diff --git a/format/devops.go b/format/devops.go index a94bf22..045d581 100644 --- a/format/devops.go +++ b/format/devops.go @@ -28,12 +28,30 @@ func (f *AzureDevOpsMarkdown) CodeBlock(language, code string) (string, error) { return formatcore.GFMCodeBlock(language, code), nil } +// Anchor produces an anchor for the provided link. +func (f *AzureDevOpsMarkdown) Anchor(anchor string) string { + return formatcore.Anchor(anchor) +} + +// AnchorHeader converts the provided text and custom anchor link into a header +// of the provided level. The level is expected to be at least 1. +func (f *AzureDevOpsMarkdown) AnchorHeader(level int, text, anchor string) (string, error) { + return formatcore.AnchorHeader(level, formatcore.Escape(text), anchor) +} + // Header converts the provided text into a header of the provided level. The // level is expected to be at least 1. func (f *AzureDevOpsMarkdown) Header(level int, text string) (string, error) { return formatcore.Header(level, formatcore.Escape(text)) } +// RawAnchorHeader converts the provided text and custom anchor link into a +// header of the provided level without escaping the header text. The level is +// expected to be at least 1. +func (f *AzureDevOpsMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) { + return formatcore.AnchorHeader(level, text, anchor) +} + // RawHeader converts the provided text into a header of the provided level // without escaping the header text. The level is expected to be at least 1. func (f *AzureDevOpsMarkdown) RawHeader(level int, text string) (string, error) { @@ -57,6 +75,12 @@ func (f *AzureDevOpsMarkdown) LocalHref(headerText string) (string, error) { return fmt.Sprintf("#%s", result), nil } +// RawLocalHref generates an href within the same document but with a direct +// link provided instead of text to slugify. +func (f *AzureDevOpsMarkdown) RawLocalHref(anchor string) string { + return fmt.Sprintf("#%s", anchor) +} + // CodeHref generates an href to the provided code entry. func (f *AzureDevOpsMarkdown) CodeHref(loc lang.Location) (string, error) { // If there's no repo, we can't compute an href @@ -131,11 +155,6 @@ func (f *AzureDevOpsMarkdown) AccordionTerminator() (string, error) { return formatcore.GFMAccordionTerminator(), nil } -// Paragraph formats a paragraph with the provided text as the contents. -func (f *AzureDevOpsMarkdown) Paragraph(text string) (string, error) { - return formatcore.Paragraph(text), nil -} - // Escape escapes special markdown characters from the provided text. func (f *AzureDevOpsMarkdown) Escape(text string) string { return formatcore.Escape(text) diff --git a/format/devops_test.go b/format/devops_test.go index 9618594..40275d9 100644 --- a/format/devops_test.go +++ b/format/devops_test.go @@ -25,7 +25,7 @@ func TestCodeBlock(t *testing.T) { var f format.AzureDevOpsMarkdown res, err := f.CodeBlock("go", "Line 1\nLine 2") is.NoErr(err) - is.Equal(res, "```go\nLine 1\nLine 2\n```\n\n") + is.Equal(res, "```go\nLine 1\nLine 2\n```") } func TestCodeBlock_noLanguage(t *testing.T) { @@ -34,7 +34,7 @@ func TestCodeBlock_noLanguage(t *testing.T) { var f format.AzureDevOpsMarkdown res, err := f.CodeBlock("", "Line 1\nLine 2") is.NoErr(err) - is.Equal(res, "```\nLine 1\nLine 2\n```\n\n") + is.Equal(res, "```\nLine 1\nLine 2\n```") } func TestHeader(t *testing.T) { @@ -43,14 +43,14 @@ func TestHeader(t *testing.T) { level int result string }{ - {"header text", 1, "# header text\n\n"}, - {"level 2", 2, "## level 2\n\n"}, - {"level 3", 3, "### level 3\n\n"}, - {"level 4", 4, "#### level 4\n\n"}, - {"level 5", 5, "##### level 5\n\n"}, - {"level 6", 6, "###### level 6\n\n"}, - {"other level", 12, "###### other level\n\n"}, - {"with * escape", 2, "## with \\* escape\n\n"}, + {"header text", 1, "# header text"}, + {"level 2", 2, "## level 2"}, + {"level 3", 3, "### level 3"}, + {"level 4", 4, "#### level 4"}, + {"level 5", 5, "##### level 5"}, + {"level 6", 6, "###### level 6"}, + {"other level", 12, "###### other level"}, + {"with * escape", 2, "## with \\* escape"}, } for _, test := range tests { @@ -79,8 +79,8 @@ func TestRawHeader(t *testing.T) { level int result string }{ - {"header text", 1, "# header text\n\n"}, - {"with * escape", 2, "## with * escape\n\n"}, + {"header text", 1, "# header text"}, + {"with * escape", 2, "## with * escape"}, } for _, test := range tests { @@ -173,7 +173,7 @@ func TestListEntry(t *testing.T) { var f format.AzureDevOpsMarkdown res, err := f.ListEntry(0, "list entry text") is.NoErr(err) - is.Equal(res, "- list entry text\n") + is.Equal(res, "- list entry text") } func TestListEntry_nested(t *testing.T) { @@ -182,7 +182,7 @@ func TestListEntry_nested(t *testing.T) { var f format.AzureDevOpsMarkdown res, err := f.ListEntry(2, "nested text") is.NoErr(err) - is.Equal(res, " - nested text\n") + is.Equal(res, " - nested text") } func TestListEntry_empty(t *testing.T) { diff --git a/format/format.go b/format/format.go index 54b37b7..969b037 100644 --- a/format/format.go +++ b/format/format.go @@ -12,10 +12,22 @@ type Format interface { // provided language (or no language if the empty string is provided). CodeBlock(language, code string) (string, error) + // Anchor produces an anchor for the provided link. + Anchor(anchor string) string + + // AnchorHeader converts the provided text and custom anchor link into a + // header of the provided level. The level is expected to be at least 1. + AnchorHeader(level int, text, anchor string) (string, error) + // Header converts the provided text into a header of the provided level. // The level is expected to be at least 1. Header(level int, text string) (string, error) + // RawAnchorHeader converts the provided text and custom anchor link into a + // header of the provided level without escaping the header text. The level + // is expected to be at least 1. + RawAnchorHeader(level int, text, anchor string) (string, error) + // RawHeader converts the provided text into a header of the provided level // without escaping the header text. The level is expected to be at least 1. RawHeader(level int, text string) (string, error) @@ -24,6 +36,10 @@ type Format interface { // headerText located within the same document as the href itself. LocalHref(headerText string) (string, error) + // RawLocalHref generates an href within the same document but with a direct + // link provided instead of text to slugify. + RawLocalHref(anchor string) string + // Link generates a link with the given text and href values. Link(text, href string) (string, error) @@ -56,9 +72,6 @@ type Format interface { // AccordionHeader(). See AccordionHeader for a full description. AccordionTerminator() (string, error) - // Paragraph formats a paragraph with the provided text as the contents. - Paragraph(text string) (string, error) - // Escape escapes special markdown characters from the provided text. Escape(text string) string } diff --git a/format/formatcore/README.md b/format/formatcore/README.md index 93c100d..620d0ae 100755 --- a/format/formatcore/README.md +++ b/format/formatcore/README.md @@ -10,21 +10,41 @@ Package formatcore provides utilities for creating formatters like those found i ## Index -- [func Bold(text string) string](<#func-bold>) -- [func CodeBlock(code string) string](<#func-codeblock>) -- [func Escape(text string) string](<#func-escape>) -- [func GFMAccordion(title, body string) string](<#func-gfmaccordion>) -- [func GFMAccordionHeader(title string) string](<#func-gfmaccordionheader>) -- [func GFMAccordionTerminator() string](<#func-gfmaccordionterminator>) -- [func GFMCodeBlock(language, code string) string](<#func-gfmcodeblock>) -- [func Header(level int, text string) (string, error)](<#func-header>) -- [func Link(text, href string) string](<#func-link>) -- [func ListEntry(depth int, text string) string](<#func-listentry>) -- [func Paragraph(text string) string](<#func-paragraph>) -- [func PlainText(text string) string](<#func-plaintext>) - - -## func [Bold]() +- [func Anchor\(anchor string\) string](<#Anchor>) +- [func AnchorHeader\(level int, text, anchor string\) \(string, error\)](<#AnchorHeader>) +- [func Bold\(text string\) string](<#Bold>) +- [func CodeBlock\(code string\) string](<#CodeBlock>) +- [func Escape\(text string\) string](<#Escape>) +- [func GFMAccordion\(title, body string\) string](<#GFMAccordion>) +- [func GFMAccordionHeader\(title string\) string](<#GFMAccordionHeader>) +- [func GFMAccordionTerminator\(\) string](<#GFMAccordionTerminator>) +- [func GFMCodeBlock\(language, code string\) string](<#GFMCodeBlock>) +- [func Header\(level int, text string\) \(string, error\)](<#Header>) +- [func Link\(text, href string\) string](<#Link>) +- [func ListEntry\(depth int, text string\) string](<#ListEntry>) +- [func PlainText\(text string\) string](<#PlainText>) + + + +## func [Anchor]() + +```go +func Anchor(anchor string) string +``` + +Anchor produces an anchor for the provided link. + + +## func [AnchorHeader]() + +```go +func AnchorHeader(level int, text, anchor string) (string, error) +``` + +AnchorHeader converts the provided text and custom anchor link into a header of the provided level. The level is expected to be at least 1. + + +## func [Bold]() ```go func Bold(text string) string @@ -32,7 +52,8 @@ func Bold(text string) string Bold converts the provided text to bold -## func [CodeBlock]() + +## func [CodeBlock]() ```go func CodeBlock(code string) string @@ -40,7 +61,8 @@ func CodeBlock(code string) string CodeBlock wraps the provided code as a code block. Language syntax highlighting is not supported. -## func [Escape]() + +## func [Escape]() ```go func Escape(text string) string @@ -48,7 +70,8 @@ func Escape(text string) string Escape escapes the special characters in the provided text, but leaves URLs found intact. Note that the URLs included must begin with a scheme to skip the escaping. -## func [GFMAccordion]() + +## func [GFMAccordion]() ```go func GFMAccordion(title, body string) string @@ -56,7 +79,8 @@ func GFMAccordion(title, body string) string GFMAccordion generates a collapsible content. The accordion's visible title while collapsed is the provided title and the expanded content is the body. -## func [GFMAccordionHeader]() + +## func [GFMAccordionHeader]() ```go func GFMAccordionHeader(title string) string @@ -70,7 +94,8 @@ The GFMAccordionHeader is expected to be used in conjunction with GFMAccordionTe accordion := GFMAccordionHeader("Accordion Title") + "Accordion Body" + GFMAccordionTerminator() ``` -## func [GFMAccordionTerminator]() + +## func [GFMAccordionTerminator]() ```go func GFMAccordionTerminator() string @@ -78,7 +103,8 @@ func GFMAccordionTerminator() string GFMAccordionTerminator generates the code necessary to terminate an accordion after the body. It is expected to be used in conjunction with GFMAccordionHeader\(\). See GFMAccordionHeader for a full description. -## func [GFMCodeBlock]() + +## func [GFMCodeBlock]() ```go func GFMCodeBlock(language, code string) string @@ -86,7 +112,8 @@ func GFMCodeBlock(language, code string) string GFMCodeBlock wraps the provided code as a code block and tags it with the provided language \(or no language if the empty string is provided\), using the triple backtick format from GitHub Flavored Markdown. -## func [Header]() + +## func [Header]() ```go func Header(level int, text string) (string, error) @@ -94,7 +121,8 @@ func Header(level int, text string) (string, error) Header converts the provided text into a header of the provided level. The level is expected to be at least 1. -## func [Link]() + +## func [Link]() ```go func Link(text, href string) string @@ -102,7 +130,8 @@ func Link(text, href string) string Link generates a link with the given text and href values. -## func [ListEntry]() + +## func [ListEntry]() ```go func ListEntry(depth int, text string) string @@ -110,15 +139,8 @@ func ListEntry(depth int, text string) string ListEntry generates an unordered list entry with the provided text at the provided zero\-indexed depth. A depth of 0 is considered the topmost level of list. -## func [Paragraph]() - -```go -func Paragraph(text string) string -``` - -Paragraph formats a paragraph with the provided text as the contents. - -## func [PlainText]() + +## func [PlainText]() ```go func PlainText(text string) string @@ -126,6 +148,4 @@ func PlainText(text string) string PlainText converts a markdown string to the plain text that appears in the rendered output. - - Generated by [gomarkdoc]() diff --git a/format/formatcore/base.go b/format/formatcore/base.go index 08e0f05..fea1066 100644 --- a/format/formatcore/base.go +++ b/format/formatcore/base.go @@ -3,6 +3,7 @@ package formatcore import ( "errors" "fmt" + "html" "regexp" "strings" @@ -34,8 +35,6 @@ func CodeBlock(code string) string { builder.WriteString(line) } - builder.WriteString("\n\n") - return builder.String() } @@ -43,7 +42,26 @@ func CodeBlock(code string) string { // provided language (or no language if the empty string is provided), using // the triple backtick format from GitHub Flavored Markdown. func GFMCodeBlock(language, code string) string { - return fmt.Sprintf("```%s\n%s\n```\n\n", language, strings.TrimSpace(code)) + return fmt.Sprintf("```%s\n%s\n```", language, strings.TrimSpace(code)) +} + +// Anchor produces an anchor for the provided link. +func Anchor(anchor string) string { + return fmt.Sprintf( + "", + html.EscapeString(anchor), + ) +} + +// AnchorHeader converts the provided text and custom anchor link into a header +// of the provided level. The level is expected to be at least 1. +func AnchorHeader(level int, text, anchor string) (string, error) { + header, err := Header(level, text) + if err != nil { + return "", err + } + + return fmt.Sprintf("%s\n%s", Anchor(anchor), header), nil } // Header converts the provided text into a header of the provided level. The @@ -55,18 +73,18 @@ func Header(level int, text string) (string, error) { switch level { case 1: - return fmt.Sprintf("# %s\n\n", text), nil + return fmt.Sprintf("# %s", text), nil case 2: - return fmt.Sprintf("## %s\n\n", text), nil + return fmt.Sprintf("## %s", text), nil case 3: - return fmt.Sprintf("### %s\n\n", text), nil + return fmt.Sprintf("### %s", text), nil case 4: - return fmt.Sprintf("#### %s\n\n", text), nil + return fmt.Sprintf("#### %s", text), nil case 5: - return fmt.Sprintf("##### %s\n\n", text), nil + return fmt.Sprintf("##### %s", text), nil default: // Only go up to 6 levels. Anything higher is also level 6 - return fmt.Sprintf("###### %s\n\n", text), nil + return fmt.Sprintf("###### %s", text), nil } } @@ -80,7 +98,7 @@ func Link(text, href string) string { return text } - return fmt.Sprintf("[%s](<%s>)", text, href) + return fmt.Sprintf("[%s](<%s>)", Escape(text), href) } // ListEntry generates an unordered list entry with the provided text at the @@ -93,13 +111,13 @@ func ListEntry(depth int, text string) string { } prefix := strings.Repeat(" ", depth) - return fmt.Sprintf("%s- %s\n", prefix, text) + return fmt.Sprintf("%s- %s", prefix, text) } // GFMAccordion generates a collapsible content. The accordion's visible title // while collapsed is the provided title and the expanded content is the body. func GFMAccordion(title, body string) string { - return fmt.Sprintf("
%s\n

\n\n%s

\n
\n\n", title, Escape(body)) + return fmt.Sprintf("
%s\n

%s

\n
", title, Escape(body)) } // GFMAccordionHeader generates the header visible when an accordion is @@ -112,19 +130,14 @@ func GFMAccordion(title, body string) string { // // accordion := GFMAccordionHeader("Accordion Title") + "Accordion Body" + GFMAccordionTerminator() func GFMAccordionHeader(title string) string { - return fmt.Sprintf("
%s\n

\n\n", title) + return fmt.Sprintf("

%s\n

", title) } // GFMAccordionTerminator generates the code necessary to terminate an // accordion after the body. It is expected to be used in conjunction with // GFMAccordionHeader(). See GFMAccordionHeader for a full description. func GFMAccordionTerminator() string { - return "

\n
\n\n" -} - -// Paragraph formats a paragraph with the provided text as the contents. -func Paragraph(text string) string { - return fmt.Sprintf("%s\n\n", Escape(text)) + return "

\n
" } var ( diff --git a/format/github.go b/format/github.go index d077efe..3268419 100644 --- a/format/github.go +++ b/format/github.go @@ -29,12 +29,30 @@ func (f *GitHubFlavoredMarkdown) CodeBlock(language, code string) (string, error return formatcore.GFMCodeBlock(language, code), nil } +// Anchor produces an anchor for the provided link. +func (f *GitHubFlavoredMarkdown) Anchor(anchor string) string { + return formatcore.Anchor(anchor) +} + +// AnchorHeader converts the provided text and custom anchor link into a header +// of the provided level. The level is expected to be at least 1. +func (f *GitHubFlavoredMarkdown) AnchorHeader(level int, text, anchor string) (string, error) { + return formatcore.AnchorHeader(level, formatcore.Escape(text), anchor) +} + // Header converts the provided text into a header of the provided level. The // level is expected to be at least 1. func (f *GitHubFlavoredMarkdown) Header(level int, text string) (string, error) { return formatcore.Header(level, formatcore.Escape(text)) } +// RawAnchorHeader converts the provided text and custom anchor link into a +// header of the provided level without escaping the header text. The level is +// expected to be at least 1. +func (f *GitHubFlavoredMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) { + return formatcore.AnchorHeader(level, text, anchor) +} + // RawHeader converts the provided text into a header of the provided level // without escaping the header text. The level is expected to be at least 1. func (f *GitHubFlavoredMarkdown) RawHeader(level int, text string) (string, error) { @@ -58,6 +76,12 @@ func (f *GitHubFlavoredMarkdown) LocalHref(headerText string) (string, error) { return fmt.Sprintf("#%s", result), nil } +// RawLocalHref generates an href within the same document but with a direct +// link provided instead of text to slugify. +func (f *GitHubFlavoredMarkdown) RawLocalHref(anchor string) string { + return fmt.Sprintf("#%s", anchor) +} + // Link generates a link with the given text and href values. func (f *GitHubFlavoredMarkdown) Link(text, href string) (string, error) { return formatcore.Link(text, href), nil @@ -140,11 +164,6 @@ func (f *GitHubFlavoredMarkdown) AccordionTerminator() (string, error) { return formatcore.GFMAccordionTerminator(), nil } -// Paragraph formats a paragraph with the provided text as the contents. -func (f *GitHubFlavoredMarkdown) Paragraph(text string) (string, error) { - return formatcore.Paragraph(text), nil -} - // Escape escapes special markdown characters from the provided text. func (f *GitHubFlavoredMarkdown) Escape(text string) string { return formatcore.Escape(text) diff --git a/format/github_test.go b/format/github_test.go index b4f47ed..6bbd5e0 100644 --- a/format/github_test.go +++ b/format/github_test.go @@ -25,7 +25,7 @@ func TestGitHubFlavoredMarkdown_CodeBlock(t *testing.T) { var f format.GitHubFlavoredMarkdown res, err := f.CodeBlock("go", "Line 1\nLine 2") is.NoErr(err) - is.Equal(res, "```go\nLine 1\nLine 2\n```\n\n") + is.Equal(res, "```go\nLine 1\nLine 2\n```") } func TestGitHubFlavoredMarkdown_CodeBlock_noLanguage(t *testing.T) { @@ -34,7 +34,7 @@ func TestGitHubFlavoredMarkdown_CodeBlock_noLanguage(t *testing.T) { var f format.GitHubFlavoredMarkdown res, err := f.CodeBlock("", "Line 1\nLine 2") is.NoErr(err) - is.Equal(res, "```\nLine 1\nLine 2\n```\n\n") + is.Equal(res, "```\nLine 1\nLine 2\n```") } func TestGitHubFlavoredMarkdown_Header(t *testing.T) { @@ -43,14 +43,14 @@ func TestGitHubFlavoredMarkdown_Header(t *testing.T) { level int result string }{ - {"header text", 1, "# header text\n\n"}, - {"level 2", 2, "## level 2\n\n"}, - {"level 3", 3, "### level 3\n\n"}, - {"level 4", 4, "#### level 4\n\n"}, - {"level 5", 5, "##### level 5\n\n"}, - {"level 6", 6, "###### level 6\n\n"}, - {"other level", 12, "###### other level\n\n"}, - {"with * escape", 2, "## with \\* escape\n\n"}, + {"header text", 1, "# header text"}, + {"level 2", 2, "## level 2"}, + {"level 3", 3, "### level 3"}, + {"level 4", 4, "#### level 4"}, + {"level 5", 5, "##### level 5"}, + {"level 6", 6, "###### level 6"}, + {"other level", 12, "###### other level"}, + {"with * escape", 2, "## with \\* escape"}, } for _, test := range tests { @@ -79,8 +79,8 @@ func TestGitHubFlavoredMarkdown_RawHeader(t *testing.T) { level int result string }{ - {"header text", 1, "# header text\n\n"}, - {"with * escape", 2, "## with * escape\n\n"}, + {"header text", 1, "# header text"}, + {"with * escape", 2, "## with * escape"}, } for _, test := range tests { @@ -173,7 +173,7 @@ func TestGitHubFlavoredMarkdown_ListEntry(t *testing.T) { var f format.GitHubFlavoredMarkdown res, err := f.ListEntry(0, "list entry text") is.NoErr(err) - is.Equal(res, "- list entry text\n") + is.Equal(res, "- list entry text") } func TestGitHubFlavoredMarkdown_ListEntry_nested(t *testing.T) { @@ -182,7 +182,7 @@ func TestGitHubFlavoredMarkdown_ListEntry_nested(t *testing.T) { var f format.GitHubFlavoredMarkdown res, err := f.ListEntry(2, "nested text") is.NoErr(err) - is.Equal(res, " - nested text\n") + is.Equal(res, " - nested text") } func TestGitHubFlavoredMarkdown_ListEntry_empty(t *testing.T) { diff --git a/format/plain.go b/format/plain.go index 1ee8bb1..0380540 100644 --- a/format/plain.go +++ b/format/plain.go @@ -22,12 +22,30 @@ func (f *PlainMarkdown) CodeBlock(language, code string) (string, error) { return formatcore.CodeBlock(code), nil } +// Anchor produces an anchor for the provided link. +func (f *PlainMarkdown) Anchor(anchor string) string { + return formatcore.Anchor(anchor) +} + +// AnchorHeader converts the provided text and custom anchor link into a header +// of the provided level. The level is expected to be at least 1. +func (f *PlainMarkdown) AnchorHeader(level int, text, anchor string) (string, error) { + return formatcore.AnchorHeader(level, formatcore.Escape(text), anchor) +} + // Header converts the provided text into a header of the provided level. The // level is expected to be at least 1. func (f *PlainMarkdown) Header(level int, text string) (string, error) { return formatcore.Header(level, formatcore.Escape(text)) } +// RawAnchorHeader converts the provided text and custom anchor link into a +// header of the provided level without escaping the header text. The level is +// expected to be at least 1. +func (f *PlainMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) { + return formatcore.AnchorHeader(level, text, anchor) +} + // RawHeader converts the provided text into a header of the provided level // without escaping the header text. The level is expected to be at least 1. func (f *PlainMarkdown) RawHeader(level int, text string) (string, error) { @@ -40,6 +58,12 @@ func (f *PlainMarkdown) LocalHref(headerText string) (string, error) { return "", nil } +// RawLocalHref generates an href within the same document but with a direct +// link provided instead of text to slugify. +func (f *PlainMarkdown) RawLocalHref(anchor string) string { + return fmt.Sprintf("#%s", anchor) +} + // CodeHref always returns the empty string, as there is no defined file linking // format in standard markdown. func (f *PlainMarkdown) CodeHref(loc lang.Location) (string, error) { @@ -66,7 +90,7 @@ func (f *PlainMarkdown) Accordion(title, body string) (string, error) { return "", err } - return fmt.Sprintf("%s%s", h, formatcore.Paragraph(body)), nil + return fmt.Sprintf("%s%s", h, body), nil } // AccordionHeader generates the header visible when an accordion is collapsed. @@ -90,11 +114,6 @@ func (f *PlainMarkdown) AccordionTerminator() (string, error) { return "\n\n", nil } -// Paragraph formats a paragraph with the provided text as the contents. -func (f *PlainMarkdown) Paragraph(text string) (string, error) { - return formatcore.Paragraph(text), nil -} - // Escape escapes special markdown characters from the provided text. func (f *PlainMarkdown) Escape(text string) string { return formatcore.Escape(text) diff --git a/format/plain_test.go b/format/plain_test.go index a510ddf..02d0b19 100644 --- a/format/plain_test.go +++ b/format/plain_test.go @@ -25,7 +25,7 @@ func TestPlainMarkdown_CodeBlock(t *testing.T) { var f format.PlainMarkdown res, err := f.CodeBlock("go", "Line 1\nLine 2") is.NoErr(err) - is.Equal(res, "\tLine 1\n\tLine 2\n\n") + is.Equal(res, "\tLine 1\n\tLine 2") } func TestPlainMarkdown_CodeBlock_noLanguage(t *testing.T) { @@ -34,7 +34,7 @@ func TestPlainMarkdown_CodeBlock_noLanguage(t *testing.T) { var f format.PlainMarkdown res, err := f.CodeBlock("", "Line 1\nLine 2") is.NoErr(err) - is.Equal(res, "\tLine 1\n\tLine 2\n\n") + is.Equal(res, "\tLine 1\n\tLine 2") } func TestPlainMarkdown_Header(t *testing.T) { @@ -43,14 +43,14 @@ func TestPlainMarkdown_Header(t *testing.T) { level int result string }{ - {"header text", 1, "# header text\n\n"}, - {"level 2", 2, "## level 2\n\n"}, - {"level 3", 3, "### level 3\n\n"}, - {"level 4", 4, "#### level 4\n\n"}, - {"level 5", 5, "##### level 5\n\n"}, - {"level 6", 6, "###### level 6\n\n"}, - {"other level", 12, "###### other level\n\n"}, - {"with * escape", 2, "## with \\* escape\n\n"}, + {"header text", 1, "# header text"}, + {"level 2", 2, "## level 2"}, + {"level 3", 3, "### level 3"}, + {"level 4", 4, "#### level 4"}, + {"level 5", 5, "##### level 5"}, + {"level 6", 6, "###### level 6"}, + {"other level", 12, "###### other level"}, + {"with * escape", 2, "## with \\* escape"}, } for _, test := range tests { @@ -79,8 +79,8 @@ func TestPlainMarkdown_RawHeader(t *testing.T) { level int result string }{ - {"header text", 1, "# header text\n\n"}, - {"with * escape", 2, "## with * escape\n\n"}, + {"header text", 1, "# header text"}, + {"with * escape", 2, "## with * escape"}, } for _, test := range tests { @@ -161,7 +161,7 @@ func TestPlainMarkdown_ListEntry(t *testing.T) { var f format.PlainMarkdown res, err := f.ListEntry(0, "list entry text") is.NoErr(err) - is.Equal(res, "- list entry text\n") + is.Equal(res, "- list entry text") } func TestPlainMarkdown_ListEntry_nested(t *testing.T) { @@ -170,7 +170,7 @@ func TestPlainMarkdown_ListEntry_nested(t *testing.T) { var f format.PlainMarkdown res, err := f.ListEntry(2, "nested text") is.NoErr(err) - is.Equal(res, " - nested text\n") + is.Equal(res, " - nested text") } func TestPlainMarkdown_ListEntry_empty(t *testing.T) { diff --git a/go.mod b/go.mod index 31451c3..5dab1cb 100644 --- a/go.mod +++ b/go.mod @@ -3,57 +3,69 @@ module github.com/Weborama/gomarkdoc go 1.18 require ( - github.com/go-git/go-git/v5 v5.3.0 - github.com/matryer/is v1.4.0 + github.com/go-git/go-git/v5 v5.8.1 + github.com/matryer/is v1.4.1 github.com/princjef/mageutil v1.0.0 + github.com/princjef/termdiff v0.1.0 github.com/russross/blackfriday/v2 v2.1.0 - github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.1.3 - github.com/spf13/viper v1.7.1 + github.com/sergi/go-diff v1.3.1 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.7.0 + github.com/spf13/viper v1.18.1 github.com/x-cray/logrus-prefixed-formatter v0.5.2 - mvdan.cc/xurls/v2 v2.2.0 + mvdan.cc/xurls/v2 v2.5.0 ) require ( - github.com/Microsoft/go-winio v0.5.0 // indirect + dario.cat/mergo v1.0.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect github.com/VividCortex/ewma v1.2.0 // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect github.com/cheggaaa/pb/v3 v3.0.8 // indirect - github.com/emirpasic/gods v1.12.0 // indirect - github.com/fatih/color v1.11.0 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.3.1 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/fatih/color v1.14.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.4.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/kevinburke/ssh_config v1.1.0 // indirect - github.com/magiconair/properties v1.8.5 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/logrusorgru/aurora/v4 v4.0.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.24.2 // indirect - github.com/pelletier/go-toml v1.9.1 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/sergi/go-diff v1.2.0 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.5.1 // indirect - github.com/subosito/gotenv v1.2.0 // indirect - github.com/xanzy/ssh-agent v0.3.0 // indirect - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.13.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 557b44d..522201b 100644 --- a/go.sum +++ b/go.sum @@ -1,218 +1,111 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cheggaaa/pb v2.0.7+incompatible/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw= github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.11.0 h1:l4iX0RqNnx/pU7rY2DB/I+znuYY0K3x6Ywac6EIr0PA= -github.com/fatih/color v1.11.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= +github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= +github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A= +github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o= -github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA= +github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/matryer/is v1.3.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= +github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -221,172 +114,111 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.1 h1:a6qW1EVNZWH9WGI6CsYdD8WAylkoXBS5yv0XHlh17Tc= -github.com/pelletier/go-toml v1.9.1/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/princjef/mageutil v1.0.0 h1:1OfZcJUMsooPqieOz2ooLjI+uHUo618pdaJsbCXcFjQ= github.com/princjef/mageutil v1.0.0/go.mod h1:mkShhaUomCYfAoVvTKRcbAs8YSVPdtezI5j6K+VXhrs= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/princjef/termdiff v0.1.0 h1:O3PWhfPFzX6GqzQ+41B3XzzJpMlx0+9Vysm+Pv76C9U= +github.com/princjef/termdiff v0.1.0/go.mod h1:JJOfCA/eR6T1JfsoxQQ6jsG3LGoQDoKUIRQrKqAO+p4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= +github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -394,72 +226,51 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -467,40 +278,28 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/VividCortex/ewma.v1 v1.1.1/go.mod h1:TekXuFipeiHWiAlO1+wSS23vTcyFau5u3rxXUSXj710= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v2 v2.0.7/go.mod h1:0CiZ1p8pvtxBlQpLXkHuUTpdJ1shm3OqCF1QugkjHL4= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fatih/color.v1 v1.7.0/go.mod h1:P7yosIhqIl/sX8J8UypY5M+dDpD2KmyfP5IRs5v/fo0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mattn/go-colorable.v0 v0.1.0/go.mod h1:BVJlBXzARQxdi3nZo6f6bnl5yR20/tOL6p+V0KejgSY= gopkg.in/mattn/go-isatty.v0 v0.0.4/go.mod h1:wt691ab7g0X4ilKZNmMII3egK0bTxl37fEn/Fwbd8gc= gopkg.in/mattn/go-runewidth.v0 v0.0.4/go.mod h1:BmXejnxvhwdaATwiJbB1vZ2dtXkQKZGu9yLFCZb4msQ= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= -mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= +mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= diff --git a/lang/README.md b/lang/README.md index e684273..7213f7f 100644 --- a/lang/README.md +++ b/lang/README.md @@ -10,93 +10,131 @@ Package lang provides constructs for defining golang language constructs and ext ## Index -- [type Block](<#type-block>) - - [func NewBlock(cfg *Config, kind BlockKind, text string) *Block](<#func-newblock>) - - [func (b *Block) Kind() BlockKind](<#func-block-kind>) - - [func (b *Block) Level() int](<#func-block-level>) - - [func (b *Block) Text() string](<#func-block-text>) -- [type BlockKind](<#type-blockkind>) -- [type Config](<#type-config>) - - [func NewConfig(log logger.Logger, workDir string, pkgDir string, opts ...ConfigOption) (*Config, error)](<#func-newconfig>) - - [func (c *Config) Inc(step int) *Config](<#func-config-inc>) -- [type ConfigOption](<#type-configoption>) - - [func ConfigWithRepoOverrides(overrides *Repo) ConfigOption](<#func-configwithrepooverrides>) -- [type Doc](<#type-doc>) - - [func NewDoc(cfg *Config, text string) *Doc](<#func-newdoc>) - - [func (d *Doc) Blocks() []*Block](<#func-doc-blocks>) - - [func (d *Doc) Level() int](<#func-doc-level>) -- [type Example](<#type-example>) - - [func NewExample(cfg *Config, name string, doc *doc.Example) *Example](<#func-newexample>) - - [func (ex *Example) Code() (string, error)](<#func-example-code>) - - [func (ex *Example) Doc() *Doc](<#func-example-doc>) - - [func (ex *Example) HasOutput() bool](<#func-example-hasoutput>) - - [func (ex *Example) Level() int](<#func-example-level>) - - [func (ex *Example) Location() Location](<#func-example-location>) - - [func (ex *Example) Name() string](<#func-example-name>) - - [func (ex *Example) Output() string](<#func-example-output>) - - [func (ex *Example) Summary() string](<#func-example-summary>) - - [func (ex *Example) Title() string](<#func-example-title>) -- [type File](<#type-file>) - - [func NewFile(header, footer string, packages []*Package) *File](<#func-newfile>) -- [type Func](<#type-func>) - - [func NewFunc(cfg *Config, doc *doc.Func, examples []*doc.Example) *Func](<#func-newfunc>) - - [func (fn *Func) Doc() *Doc](<#func-func-doc>) - - [func (fn *Func) Examples() (examples []*Example)](<#func-func-examples>) - - [func (fn *Func) Level() int](<#func-func-level>) - - [func (fn *Func) Location() Location](<#func-func-location>) - - [func (fn *Func) Name() string](<#func-func-name>) - - [func (fn *Func) Receiver() string](<#func-func-receiver>) - - [func (fn *Func) Signature() (string, error)](<#func-func-signature>) - - [func (fn *Func) Summary() string](<#func-func-summary>) - - [func (fn *Func) Title() string](<#func-func-title>) -- [type Location](<#type-location>) - - [func NewLocation(cfg *Config, node ast.Node) Location](<#func-newlocation>) -- [type Package](<#type-package>) - - [func NewPackage(cfg *Config, doc *doc.Package, examples []*doc.Example) *Package](<#func-newpackage>) - - [func NewPackageFromBuild(log logger.Logger, pkg *build.Package, opts ...PackageOption) (*Package, error)](<#func-newpackagefrombuild>) - - [func (pkg *Package) Consts() (consts []*Value)](<#func-package-consts>) - - [func (pkg *Package) Dir() string](<#func-package-dir>) - - [func (pkg *Package) Dirname() string](<#func-package-dirname>) - - [func (pkg *Package) Doc() *Doc](<#func-package-doc>) - - [func (pkg *Package) Examples() (examples []*Example)](<#func-package-examples>) - - [func (pkg *Package) Funcs() (funcs []*Func)](<#func-package-funcs>) - - [func (pkg *Package) Import() string](<#func-package-import>) - - [func (pkg *Package) ImportPath() string](<#func-package-importpath>) - - [func (pkg *Package) Level() int](<#func-package-level>) - - [func (pkg *Package) Name() string](<#func-package-name>) - - [func (pkg *Package) Summary() string](<#func-package-summary>) - - [func (pkg *Package) Types() (types []*Type)](<#func-package-types>) - - [func (pkg *Package) Vars() (vars []*Value)](<#func-package-vars>) -- [type PackageOption](<#type-packageoption>) - - [func PackageWithRepositoryOverrides(repo *Repo) PackageOption](<#func-packagewithrepositoryoverrides>) - - [func PackageWithUnexportedIncluded() PackageOption](<#func-packagewithunexportedincluded>) -- [type PackageOptions](<#type-packageoptions>) -- [type Position](<#type-position>) -- [type Repo](<#type-repo>) -- [type Type](<#type-type>) - - [func NewType(cfg *Config, doc *doc.Type, examples []*doc.Example) *Type](<#func-newtype>) - - [func (typ *Type) Consts() []*Value](<#func-type-consts>) - - [func (typ *Type) Decl() (string, error)](<#func-type-decl>) - - [func (typ *Type) Doc() *Doc](<#func-type-doc>) - - [func (typ *Type) Examples() (examples []*Example)](<#func-type-examples>) - - [func (typ *Type) Funcs() []*Func](<#func-type-funcs>) - - [func (typ *Type) Level() int](<#func-type-level>) - - [func (typ *Type) Location() Location](<#func-type-location>) - - [func (typ *Type) Methods() []*Func](<#func-type-methods>) - - [func (typ *Type) Name() string](<#func-type-name>) - - [func (typ *Type) Summary() string](<#func-type-summary>) - - [func (typ *Type) Title() string](<#func-type-title>) - - [func (typ *Type) Vars() []*Value](<#func-type-vars>) -- [type Value](<#type-value>) - - [func NewValue(cfg *Config, doc *doc.Value) *Value](<#func-newvalue>) - - [func (v *Value) Decl() (string, error)](<#func-value-decl>) - - [func (v *Value) Doc() *Doc](<#func-value-doc>) - - [func (v *Value) Level() int](<#func-value-level>) - - [func (v *Value) Location() Location](<#func-value-location>) - - [func (v *Value) Summary() string](<#func-value-summary>) - - -## type [Block]() +- [func PackageSymbols\(pkg \*doc.Package\) map\[string\]Symbol](<#PackageSymbols>) +- [type Block](<#Block>) + - [func NewBlock\(cfg \*Config, kind BlockKind, spans \[\]\*Span, inline bool\) \*Block](<#NewBlock>) + - [func NewListBlock\(cfg \*Config, list \*List, inline bool\) \*Block](<#NewListBlock>) + - [func ParseBlocks\(cfg \*Config, blocks \[\]comment.Block, inline bool\) \[\]\*Block](<#ParseBlocks>) + - [func \(b \*Block\) Inline\(\) bool](<#Block.Inline>) + - [func \(b \*Block\) Kind\(\) BlockKind](<#Block.Kind>) + - [func \(b \*Block\) Level\(\) int](<#Block.Level>) + - [func \(b \*Block\) List\(\) \*List](<#Block.List>) + - [func \(b \*Block\) Spans\(\) \[\]\*Span](<#Block.Spans>) +- [type BlockKind](<#BlockKind>) +- [type Config](<#Config>) + - [func NewConfig\(log logger.Logger, workDir string, pkgDir string, opts ...ConfigOption\) \(\*Config, error\)](<#NewConfig>) + - [func \(c \*Config\) Inc\(step int\) \*Config](<#Config.Inc>) +- [type ConfigOption](<#ConfigOption>) + - [func ConfigWithRepoOverrides\(overrides \*Repo\) ConfigOption](<#ConfigWithRepoOverrides>) +- [type Doc](<#Doc>) + - [func NewDoc\(cfg \*Config, text string\) \*Doc](<#NewDoc>) + - [func \(d \*Doc\) Blocks\(\) \[\]\*Block](<#Doc.Blocks>) + - [func \(d \*Doc\) Level\(\) int](<#Doc.Level>) +- [type Example](<#Example>) + - [func NewExample\(cfg \*Config, name string, doc \*doc.Example\) \*Example](<#NewExample>) + - [func \(ex \*Example\) Code\(\) \(string, error\)](<#Example.Code>) + - [func \(ex \*Example\) Doc\(\) \*Doc](<#Example.Doc>) + - [func \(ex \*Example\) HasOutput\(\) bool](<#Example.HasOutput>) + - [func \(ex \*Example\) Level\(\) int](<#Example.Level>) + - [func \(ex \*Example\) Location\(\) Location](<#Example.Location>) + - [func \(ex \*Example\) Name\(\) string](<#Example.Name>) + - [func \(ex \*Example\) Output\(\) string](<#Example.Output>) + - [func \(ex \*Example\) Summary\(\) string](<#Example.Summary>) + - [func \(ex \*Example\) Title\(\) string](<#Example.Title>) +- [type File](<#File>) + - [func NewFile\(header, footer string, packages \[\]\*Package\) \*File](<#NewFile>) +- [type Func](<#Func>) + - [func NewFunc\(cfg \*Config, doc \*doc.Func, examples \[\]\*doc.Example\) \*Func](<#NewFunc>) + - [func \(fn \*Func\) Anchor\(\) string](<#Func.Anchor>) + - [func \(fn \*Func\) Doc\(\) \*Doc](<#Func.Doc>) + - [func \(fn \*Func\) Examples\(\) \(examples \[\]\*Example\)](<#Func.Examples>) + - [func \(fn \*Func\) Level\(\) int](<#Func.Level>) + - [func \(fn \*Func\) Location\(\) Location](<#Func.Location>) + - [func \(fn \*Func\) Name\(\) string](<#Func.Name>) + - [func \(fn \*Func\) Receiver\(\) string](<#Func.Receiver>) + - [func \(fn \*Func\) Signature\(\) \(string, error\)](<#Func.Signature>) + - [func \(fn \*Func\) Summary\(\) string](<#Func.Summary>) + - [func \(fn \*Func\) Title\(\) string](<#Func.Title>) +- [type Item](<#Item>) + - [func NewItem\(cfg \*Config, docItem \*comment.ListItem\) \*Item](<#NewItem>) + - [func \(i \*Item\) Blocks\(\) \[\]\*Block](<#Item.Blocks>) + - [func \(i \*Item\) Kind\(\) ItemKind](<#Item.Kind>) + - [func \(i \*Item\) Number\(\) int](<#Item.Number>) +- [type ItemKind](<#ItemKind>) +- [type List](<#List>) + - [func NewList\(cfg \*Config, docList \*comment.List\) \*List](<#NewList>) + - [func \(l \*List\) BlankBetween\(\) bool](<#List.BlankBetween>) + - [func \(l \*List\) Items\(\) \[\]\*Item](<#List.Items>) +- [type Location](<#Location>) + - [func NewLocation\(cfg \*Config, node ast.Node\) Location](<#NewLocation>) +- [type Package](<#Package>) + - [func NewPackage\(cfg \*Config, examples \[\]\*doc.Example\) \*Package](<#NewPackage>) + - [func NewPackageFromBuild\(log logger.Logger, pkg \*build.Package, opts ...PackageOption\) \(\*Package, error\)](<#NewPackageFromBuild>) + - [func \(pkg \*Package\) Consts\(\) \(consts \[\]\*Value\)](<#Package.Consts>) + - [func \(pkg \*Package\) Dir\(\) string](<#Package.Dir>) + - [func \(pkg \*Package\) Dirname\(\) string](<#Package.Dirname>) + - [func \(pkg \*Package\) Doc\(\) \*Doc](<#Package.Doc>) + - [func \(pkg \*Package\) Examples\(\) \(examples \[\]\*Example\)](<#Package.Examples>) + - [func \(pkg \*Package\) Funcs\(\) \(funcs \[\]\*Func\)](<#Package.Funcs>) + - [func \(pkg \*Package\) Import\(\) string](<#Package.Import>) + - [func \(pkg \*Package\) ImportPath\(\) string](<#Package.ImportPath>) + - [func \(pkg \*Package\) Level\(\) int](<#Package.Level>) + - [func \(pkg \*Package\) Name\(\) string](<#Package.Name>) + - [func \(pkg \*Package\) Summary\(\) string](<#Package.Summary>) + - [func \(pkg \*Package\) Types\(\) \(types \[\]\*Type\)](<#Package.Types>) + - [func \(pkg \*Package\) Vars\(\) \(vars \[\]\*Value\)](<#Package.Vars>) +- [type PackageOption](<#PackageOption>) + - [func PackageWithRepositoryOverrides\(repo \*Repo\) PackageOption](<#PackageWithRepositoryOverrides>) + - [func PackageWithUnexportedIncluded\(\) PackageOption](<#PackageWithUnexportedIncluded>) +- [type PackageOptions](<#PackageOptions>) +- [type Position](<#Position>) +- [type Repo](<#Repo>) +- [type Span](<#Span>) + - [func NewSpan\(cfg \*Config, kind SpanKind, text string, url string\) \*Span](<#NewSpan>) + - [func ParseSpans\(cfg \*Config, texts \[\]comment.Text\) \[\]\*Span](<#ParseSpans>) + - [func \(s \*Span\) Kind\(\) SpanKind](<#Span.Kind>) + - [func \(s \*Span\) Text\(\) string](<#Span.Text>) + - [func \(s \*Span\) URL\(\) string](<#Span.URL>) +- [type SpanKind](<#SpanKind>) +- [type Symbol](<#Symbol>) + - [func \(s Symbol\) Anchor\(\) string](<#Symbol.Anchor>) +- [type SymbolKind](<#SymbolKind>) +- [type Type](<#Type>) + - [func NewType\(cfg \*Config, doc \*doc.Type, examples \[\]\*doc.Example\) \*Type](<#NewType>) + - [func \(typ \*Type\) Anchor\(\) string](<#Type.Anchor>) + - [func \(typ \*Type\) Consts\(\) \[\]\*Value](<#Type.Consts>) + - [func \(typ \*Type\) Decl\(\) \(string, error\)](<#Type.Decl>) + - [func \(typ \*Type\) Doc\(\) \*Doc](<#Type.Doc>) + - [func \(typ \*Type\) Examples\(\) \(examples \[\]\*Example\)](<#Type.Examples>) + - [func \(typ \*Type\) Funcs\(\) \[\]\*Func](<#Type.Funcs>) + - [func \(typ \*Type\) Level\(\) int](<#Type.Level>) + - [func \(typ \*Type\) Location\(\) Location](<#Type.Location>) + - [func \(typ \*Type\) Methods\(\) \[\]\*Func](<#Type.Methods>) + - [func \(typ \*Type\) Name\(\) string](<#Type.Name>) + - [func \(typ \*Type\) Summary\(\) string](<#Type.Summary>) + - [func \(typ \*Type\) Title\(\) string](<#Type.Title>) + - [func \(typ \*Type\) Vars\(\) \[\]\*Value](<#Type.Vars>) +- [type Value](<#Value>) + - [func NewValue\(cfg \*Config, doc \*doc.Value\) \*Value](<#NewValue>) + - [func \(v \*Value\) Anchor\(\) string](<#Value.Anchor>) + - [func \(v \*Value\) Decl\(\) \(string, error\)](<#Value.Decl>) + - [func \(v \*Value\) Doc\(\) \*Doc](<#Value.Doc>) + - [func \(v \*Value\) Level\(\) int](<#Value.Level>) + - [func \(v \*Value\) Location\(\) Location](<#Value.Location>) + - [func \(v \*Value\) Summary\(\) string](<#Value.Summary>) + + + +## func [PackageSymbols]() + +```go +func PackageSymbols(pkg *doc.Package) map[string]Symbol +``` + +PackageSymbols gets the list of symbols for a doc package. + + +## type [Block]() Block defines a single block element \(e.g. paragraph, code block\) in the documentation for a symbol or package. @@ -106,15 +144,44 @@ type Block struct { } ``` -### func [NewBlock]() + +### func [NewBlock]() ```go -func NewBlock(cfg *Config, kind BlockKind, text string) *Block +func NewBlock(cfg *Config, kind BlockKind, spans []*Span, inline bool) *Block ``` -NewBlock creates a new block element of the provided kind and with the given text contents. +NewBlock creates a new block element of the provided kind and with the given text spans and a flag indicating whether this block is part of an inline element. -### func \(\*Block\) [Kind]() + +### func [NewListBlock]() + +```go +func NewListBlock(cfg *Config, list *List, inline bool) *Block +``` + +NewListBlock creates a new list block element and with the given list definition and a flag indicating whether this block is part of an inline element. + + +### func [ParseBlocks]() + +```go +func ParseBlocks(cfg *Config, blocks []comment.Block, inline bool) []*Block +``` + +ParseBlocks produces a set of blocks from the corresponding comment blocks. It also takes a flag indicating whether the blocks are part of an inline element such as a list item. + + +### func \(\*Block\) [Inline]() + +```go +func (b *Block) Inline() bool +``` + +Inline indicates whether the block is part of an inline element, such as a list item. + + +### func \(\*Block\) [Kind]() ```go func (b *Block) Kind() BlockKind @@ -122,7 +189,8 @@ func (b *Block) Kind() BlockKind Kind provides the kind of data that this block's text should be interpreted as. -### func \(\*Block\) [Level]() + +### func \(\*Block\) [Level]() ```go func (b *Block) Level() int @@ -130,15 +198,26 @@ func (b *Block) Level() int Level provides the default level that a block of kind HeaderBlock will render at in the output. The level is not used for other block types. -### func \(\*Block\) [Text]() + +### func \(\*Block\) [List]() + +```go +func (b *Block) List() *List +``` + +List provides the list contents for a list block. Only relevant for blocks of type ListBlock. + + +### func \(\*Block\) [Spans]() ```go -func (b *Block) Text() string +func (b *Block) Spans() []*Span ``` -Text provides the raw text of the block's contents. The text is pre\-scrubbed and sanitized as determined by the block's Kind\(\), but it is not wrapped in any special constructs for rendering purposes \(such as markdown code blocks\). +Spans provides the raw text of the block's contents as a set of text spans. The text is pre\-scrubbed and sanitized as determined by the block's Kind\(\), but it is not wrapped in any special constructs for rendering purposes \(such as markdown code blocks\). -## type [BlockKind]() + +## type [BlockKind]() BlockKind identifies the type of block element represented by the corresponding Block. @@ -146,6 +225,8 @@ BlockKind identifies the type of block element represented by the corresponding type BlockKind string ``` + + ```go const ( // ParagraphBlock defines a block that represents a paragraph of text. @@ -156,25 +237,33 @@ const ( // HeaderBlock defines a block that represents a section header. HeaderBlock BlockKind = "header" + + // ListBlock defines a block that represents an ordered or unordered list. + ListBlock BlockKind = "list" ) ``` -## type [Config]() + +## type [Config]() Config defines contextual information used to resolve documentation for a construct. ```go type Config struct { FileSet *token.FileSet + Files []*ast.File Level int Repo *Repo PkgDir string WorkDir string + Symbols map[string]Symbol + Pkg *doc.Package Log logger.Logger } ``` -### func [NewConfig]() + +### func [NewConfig]() ```go func NewConfig(log logger.Logger, workDir string, pkgDir string, opts ...ConfigOption) (*Config, error) @@ -182,7 +271,8 @@ func NewConfig(log logger.Logger, workDir string, pkgDir string, opts ...ConfigO NewConfig generates a Config for the provided package directory. It will resolve the filepath and attempt to determine the repository containing the directory. If no repository is found, the Repo field will be set to nil. An error is returned if the provided directory is invalid. -### func \(\*Config\) [Inc]() + +### func \(\*Config\) [Inc]() ```go func (c *Config) Inc(step int) *Config @@ -190,7 +280,8 @@ func (c *Config) Inc(step int) *Config Inc copies the Config and increments the level by the provided step. -## type [ConfigOption]() + +## type [ConfigOption]() ConfigOption modifies the Config generated by NewConfig. @@ -198,7 +289,8 @@ ConfigOption modifies the Config generated by NewConfig. type ConfigOption func(c *Config) error ``` -### func [ConfigWithRepoOverrides]() + +### func [ConfigWithRepoOverrides]() ```go func ConfigWithRepoOverrides(overrides *Repo) ConfigOption @@ -206,7 +298,8 @@ func ConfigWithRepoOverrides(overrides *Repo) ConfigOption ConfigWithRepoOverrides defines a set of manual overrides for the repository information to be used in place of automatic repository detection. -## type [Doc]() + +## type [Doc]() Doc provides access to the documentation comment contents for a package or symbol in a structured form. @@ -216,7 +309,8 @@ type Doc struct { } ``` -### func [NewDoc]() + +### func [NewDoc]() ```go func NewDoc(cfg *Config, text string) *Doc @@ -224,7 +318,8 @@ func NewDoc(cfg *Config, text string) *Doc NewDoc initializes a Doc struct from the provided raw documentation text and with headers rendered by default at the heading level provided. Documentation is separated into block level elements using the standard rules from golang's documentation conventions. -### func \(\*Doc\) [Blocks]() + +### func \(\*Doc\) [Blocks]() ```go func (d *Doc) Blocks() []*Block @@ -232,7 +327,8 @@ func (d *Doc) Blocks() []*Block Blocks holds the list of block elements that makes up the documentation contents. -### func \(\*Doc\) [Level]() + +### func \(\*Doc\) [Level]() ```go func (d *Doc) Level() int @@ -240,6 +336,7 @@ func (d *Doc) Level() int Level provides the default level that headers within the documentation should be rendered + ## type [Example]() Example holds a single documentation example for a package or symbol. @@ -250,6 +347,7 @@ type Example struct { } ``` + ### func [NewExample]() ```go @@ -258,6 +356,7 @@ func NewExample(cfg *Config, name string, doc *doc.Example) *Example NewExample creates a new example from the example function's name, its documentation example and the files holding code related to the example. + ### func \(\*Example\) [Code]() ```go @@ -266,6 +365,7 @@ func (ex *Example) Code() (string, error) Code provides the raw text code representation of the example's contents. + ### func \(\*Example\) [Doc]() ```go @@ -274,7 +374,8 @@ func (ex *Example) Doc() *Doc Doc provides the structured contents of the documentation comment for the example. -### func \(\*Example\) [HasOutput]() + +### func \(\*Example\) [HasOutput]() ```go func (ex *Example) HasOutput() bool @@ -282,6 +383,7 @@ func (ex *Example) HasOutput() bool HasOutput indicates whether the example contains any example output. + ### func \(\*Example\) [Level]() ```go @@ -290,6 +392,7 @@ func (ex *Example) Level() int Level provides the default level that headers for the example should be rendered. + ### func \(\*Example\) [Location]() ```go @@ -298,6 +401,7 @@ func (ex *Example) Location() Location Location returns a representation of the node's location in a file within a repository. + ### func \(\*Example\) [Name]() ```go @@ -306,7 +410,8 @@ func (ex *Example) Name() string Name provides a pretty\-printed name for the specific example, if one was provided. -### func \(\*Example\) [Output]() + +### func \(\*Example\) [Output]() ```go func (ex *Example) Output() string @@ -314,6 +419,7 @@ func (ex *Example) Output() string Output provides the code's example output. + ### func \(\*Example\) [Summary]() ```go @@ -322,6 +428,7 @@ func (ex *Example) Summary() string Summary provides the one\-sentence summary of the example's documentation comment. + ### func \(\*Example\) [Title]() ```go @@ -330,6 +437,7 @@ func (ex *Example) Title() string Title provides a formatted string to print as the title of the example. It incorporates the example's name, if present. + ## type [File]() File holds information for rendering a single file that contains one or more packages. @@ -342,6 +450,7 @@ type File struct { } ``` + ### func [NewFile]() ```go @@ -350,6 +459,7 @@ func NewFile(header, footer string, packages []*Package) *File NewFile creates a new instance of File with the provided information. + ## type [Func]() Func holds documentation information for a single func declaration within a package or type. @@ -360,6 +470,7 @@ type Func struct { } ``` + ### func [NewFunc]() ```go @@ -368,6 +479,16 @@ func NewFunc(cfg *Config, doc *doc.Func, examples []*doc.Example) *Func NewFunc creates a new Func from the corresponding documentation construct from the standard library, the related token.FileSet for the package and the list of examples for the package. + +### func \(\*Func\) [Anchor]() + +```go +func (fn *Func) Anchor() string +``` + +Anchor produces anchor text for the func. + + ### func \(\*Func\) [Doc]() ```go @@ -376,6 +497,7 @@ func (fn *Func) Doc() *Doc Doc provides the structured contents of the documentation comment for the function. + ### func \(\*Func\) [Examples]() ```go @@ -384,6 +506,7 @@ func (fn *Func) Examples() (examples []*Example) Examples provides the list of examples from the list given on initialization that pertain to the function. + ### func \(\*Func\) [Level]() ```go @@ -392,6 +515,7 @@ func (fn *Func) Level() int Level provides the default level at which headers for the func should be rendered in the final documentation. + ### func \(\*Func\) [Location]() ```go @@ -400,6 +524,7 @@ func (fn *Func) Location() Location Location returns a representation of the node's location in a file within a repository. + ### func \(\*Func\) [Name]() ```go @@ -408,6 +533,7 @@ func (fn *Func) Name() string Name provides the name of the function. + ### func \(\*Func\) [Receiver]() ```go @@ -416,6 +542,7 @@ func (fn *Func) Receiver() string Receiver provides the type of the receiver for the function, or empty string if there is no receiver type. + ### func \(\*Func\) [Signature]() ```go @@ -424,6 +551,7 @@ func (fn *Func) Signature() (string, error) Signature provides the raw text representation of the code for the function's signature. + ### func \(\*Func\) [Summary]() ```go @@ -432,6 +560,7 @@ func (fn *Func) Summary() string Summary provides the one\-sentence summary of the function's documentation comment + ### func \(\*Func\) [Title]() ```go @@ -440,7 +569,114 @@ func (fn *Func) Title() string Title provides the formatted name of the func. It is primarily designed for generating headers. -## type [Location]() + +## type [Item]() + +Item defines a single item in a list in the documentation for a symbol or package. + +```go +type Item struct { + // contains filtered or unexported fields +} +``` + + +### func [NewItem]() + +```go +func NewItem(cfg *Config, docItem *comment.ListItem) *Item +``` + +NewItem initializes a list item from the equivalent type from the comment package. + + +### func \(\*Item\) [Blocks]() + +```go +func (i *Item) Blocks() []*Block +``` + +Blocks returns the blocks of documentation in a list item. + + +### func \(\*Item\) [Kind]() + +```go +func (i *Item) Kind() ItemKind +``` + +Kind returns the kind of the list item. + + +### func \(\*Item\) [Number]() + +```go +func (i *Item) Number() int +``` + +Number returns the number of the list item. Only populated if the item is of the OrderedItem kind. + + +## type [ItemKind]() + +ItemKind identifies the kind of item + +```go +type ItemKind string +``` + + + +```go +const ( + // OrderedItem identifies an ordered (i.e. numbered) item. + OrderedItem ItemKind = "ordered" + + // UnorderedItem identifies an unordered (i.e. bulletted) item. + UnorderedItem ItemKind = "unordered" +) +``` + + +## type [List]() + +List defines a list block element in the documentation for a symbol or package. + +```go +type List struct { + // contains filtered or unexported fields +} +``` + + +### func [NewList]() + +```go +func NewList(cfg *Config, docList *comment.List) *List +``` + +NewList initializes a list from the equivalent type from the comment package. + + +### func \(\*List\) [BlankBetween]() + +```go +func (l *List) BlankBetween() bool +``` + +BlankBetween returns true if there should be a blank line between list items. + + +### func \(\*List\) [Items]() + +```go +func (l *List) Items() []*Item +``` + +Items returns the slice of items in the list. + + +## type [Location]() Location holds information for identifying a position within a file and repository, if present. @@ -454,7 +690,8 @@ type Location struct { } ``` -### func [NewLocation]() + +### func [NewLocation]() ```go func NewLocation(cfg *Config, node ast.Node) Location @@ -462,6 +699,7 @@ func NewLocation(cfg *Config, node ast.Node) Location NewLocation returns a location for the provided Config and ast.Node combination. This is typically not called directly, but is made available via the Location\(\) methods of various lang constructs. + ## type [Package]() Package holds documentation information for a package and all of the symbols contained within it. @@ -472,14 +710,16 @@ type Package struct { } ``` + ### func [NewPackage]() ```go -func NewPackage(cfg *Config, doc *doc.Package, examples []*doc.Example) *Package +func NewPackage(cfg *Config, examples []*doc.Example) *Package ``` NewPackage creates a representation of a package's documentation from the raw documentation constructs provided by the standard library. This is only recommended for advanced scenarios. Most consumers will find it easier to use NewPackageFromBuild instead. + ### func [NewPackageFromBuild]() ```go @@ -488,7 +728,8 @@ func NewPackageFromBuild(log logger.Logger, pkg *build.Package, opts ...PackageO NewPackageFromBuild creates a representation of a package's documentation from the build metadata for that package. It can be configured using the provided options. -### func \(\*Package\) [Consts]() + +### func \(\*Package\) [Consts]() ```go func (pkg *Package) Consts() (consts []*Value) @@ -496,7 +737,8 @@ func (pkg *Package) Consts() (consts []*Value) Consts lists the top\-level constants provided by the package. -### func \(\*Package\) [Dir]() + +### func \(\*Package\) [Dir]() ```go func (pkg *Package) Dir() string @@ -504,7 +746,8 @@ func (pkg *Package) Dir() string Dir provides the name of the full directory in which the package is located. -### func \(\*Package\) [Dirname]() + +### func \(\*Package\) [Dirname]() ```go func (pkg *Package) Dirname() string @@ -512,7 +755,8 @@ func (pkg *Package) Dirname() string Dirname provides the name of the leaf directory in which the package is located. -### func \(\*Package\) [Doc]() + +### func \(\*Package\) [Doc]() ```go func (pkg *Package) Doc() *Doc @@ -520,7 +764,8 @@ func (pkg *Package) Doc() *Doc Doc provides the structured contents of the documentation comment for the package. -### func \(\*Package\) [Examples]() + +### func \(\*Package\) [Examples]() ```go func (pkg *Package) Examples() (examples []*Example) @@ -528,7 +773,8 @@ func (pkg *Package) Examples() (examples []*Example) Examples provides the package\-level examples that have been defined. This does not include examples that are associated with symbols contained within the package. -### func \(\*Package\) [Funcs]() + +### func \(\*Package\) [Funcs]() ```go func (pkg *Package) Funcs() (funcs []*Func) @@ -536,7 +782,8 @@ func (pkg *Package) Funcs() (funcs []*Func) Funcs lists the top\-level functions provided by the package. -### func \(\*Package\) [Import]() + +### func \(\*Package\) [Import]() ```go func (pkg *Package) Import() string @@ -544,7 +791,8 @@ func (pkg *Package) Import() string Import provides the raw text for the import declaration that is used to import code from the package. If your package's documentation is generated from a local path and does not use Go Modules, this will typically print \`import "."\`. -### func \(\*Package\) [ImportPath]() + +### func \(\*Package\) [ImportPath]() ```go func (pkg *Package) ImportPath() string @@ -552,7 +800,8 @@ func (pkg *Package) ImportPath() string ImportPath provides the identifier used for the package when installing or importing the package. If your package's documentation is generated from a local path and does not use Go Modules, this will typically print \`.\`. -### func \(\*Package\) [Level]() + +### func \(\*Package\) [Level]() ```go func (pkg *Package) Level() int @@ -560,7 +809,8 @@ func (pkg *Package) Level() int Level provides the default level that headers for the package's root documentation should be rendered. -### func \(\*Package\) [Name]() + +### func \(\*Package\) [Name]() ```go func (pkg *Package) Name() string @@ -568,7 +818,8 @@ func (pkg *Package) Name() string Name provides the name of the package as it would be seen from another package importing it. -### func \(\*Package\) [Summary]() + +### func \(\*Package\) [Summary]() ```go func (pkg *Package) Summary() string @@ -576,7 +827,8 @@ func (pkg *Package) Summary() string Summary provides the one\-sentence summary of the package's documentation comment. -### func \(\*Package\) [Types]() + +### func \(\*Package\) [Types]() ```go func (pkg *Package) Types() (types []*Type) @@ -584,7 +836,8 @@ func (pkg *Package) Types() (types []*Type) Types lists the top\-level types provided by the package. -### func \(\*Package\) [Vars]() + +### func \(\*Package\) [Vars]() ```go func (pkg *Package) Vars() (vars []*Value) @@ -592,6 +845,7 @@ func (pkg *Package) Vars() (vars []*Value) Vars lists the top\-level variables provided by the package. + ## type [PackageOption]() PackageOption configures one or more options for the package. @@ -600,7 +854,8 @@ PackageOption configures one or more options for the package. type PackageOption func(opts *PackageOptions) error ``` -### func [PackageWithRepositoryOverrides]() + +### func [PackageWithRepositoryOverrides]() ```go func PackageWithRepositoryOverrides(repo *Repo) PackageOption @@ -608,7 +863,8 @@ func PackageWithRepositoryOverrides(repo *Repo) PackageOption PackageWithRepositoryOverrides can be used along with the NewPackageFromBuild function to define manual overrides to the automatic repository detection logic. -### func [PackageWithUnexportedIncluded]() + +### func [PackageWithUnexportedIncluded]() ```go func PackageWithUnexportedIncluded() PackageOption @@ -616,6 +872,7 @@ func PackageWithUnexportedIncluded() PackageOption PackageWithUnexportedIncluded can be used along with the NewPackageFromBuild function to specify that all symbols, including unexported ones, should be included in the documentation for the package. + ## type [PackageOptions]() PackageOptions holds options related to the configuration of the package and its documentation on creation. @@ -626,7 +883,8 @@ type PackageOptions struct { } ``` -## type [Position]() + +## type [Position]() Position represents a line and column number within a file. @@ -637,7 +895,8 @@ type Position struct { } ``` -## type [Repo]() + +## type [Repo]() Repo represents information about a repository relevant to documentation generation. @@ -649,6 +908,140 @@ type Repo struct { } ``` + +## type [Span]() + +Span defines a single text span in a block for documentation of a symbol or package. + +```go +type Span struct { + // contains filtered or unexported fields +} +``` + + +### func [NewSpan]() + +```go +func NewSpan(cfg *Config, kind SpanKind, text string, url string) *Span +``` + +NewSpan creates a new span. + + +### func [ParseSpans]() + +```go +func ParseSpans(cfg *Config, texts []comment.Text) []*Span +``` + +ParseSpans turns a set of \*comment.Text entries into a slice of spans. + + +### func \(\*Span\) [Kind]() + +```go +func (s *Span) Kind() SpanKind +``` + +Kind provides the kind of data that this span represents. + + +### func \(\*Span\) [Text]() + +```go +func (s *Span) Text() string +``` + +Text provides the raw text for the span. + + +### func \(\*Span\) [URL]() + +```go +func (s *Span) URL() string +``` + +URL provides the url associated with the span, if any. + + +## type [SpanKind]() + +SpanKind identifies the type of span element represented by the corresponding Span. + +```go +type SpanKind string +``` + + + +```go +const ( + // TextSpan defines a span that represents plain text. + TextSpan SpanKind = "text" + + // RawTextSpan defines a span that represents plain text that should be + // displayed as-is. + RawTextSpan SpanKind = "rawText" + + // LinkSpan defines a span that represents a link. + LinkSpan SpanKind = "link" + + // AutolinkSpan defines a span that represents text which is itself a link. + AutolinkSpan SpanKind = "autolink" +) +``` + + +## type [Symbol]() + +Symbol provides identity information for a symbol in a package. + +```go +type Symbol struct { + // Receiver holds the receiver for a method or field. + Receiver string + // Name holds the name of the symbol itself. + Name string + // Kind identifies the category of the symbol. + Kind SymbolKind + // Parent holds the linkable parent symbol which contains this one. + Parent *Symbol +} +``` + + +### func \(Symbol\) [Anchor]() + +```go +func (s Symbol) Anchor() string +``` + +Anchor produces anchor text for the symbol. + + +## type [SymbolKind]() + +SymbolKind identifies the type of symbol. + +```go +type SymbolKind int +``` + +The list of valid symbol kinds. + +```go +const ( + TypeSymbolKind SymbolKind = iota + 1 + FuncSymbolKind + ConstSymbolKind + VarSymbolKind + MethodSymbolKind + FieldSymbolKind +) +``` + + ## type [Type]() Type holds documentation information for a type declaration. @@ -659,6 +1052,7 @@ type Type struct { } ``` + ### func [NewType]() ```go @@ -667,6 +1061,16 @@ func NewType(cfg *Config, doc *doc.Type, examples []*doc.Example) *Type NewType creates a Type from the raw documentation representation of the type, the token.FileSet for the package's files and the full list of examples from the containing package. + +### func \(\*Type\) [Anchor]() + +```go +func (typ *Type) Anchor() string +``` + +Anchor produces anchor text for the type. + + ### func \(\*Type\) [Consts]() ```go @@ -675,6 +1079,7 @@ func (typ *Type) Consts() []*Value Consts lists the const declaration blocks containing values of this type. + ### func \(\*Type\) [Decl]() ```go @@ -683,6 +1088,7 @@ func (typ *Type) Decl() (string, error) Decl provides the raw text representation of the code for the type's declaration. + ### func \(\*Type\) [Doc]() ```go @@ -691,6 +1097,7 @@ func (typ *Type) Doc() *Doc Doc provides the structured contents of the documentation comment for the type. + ### func \(\*Type\) [Examples]() ```go @@ -699,6 +1106,7 @@ func (typ *Type) Examples() (examples []*Example) Examples lists the examples pertaining to the type from the set provided on initialization. + ### func \(\*Type\) [Funcs]() ```go @@ -707,6 +1115,7 @@ func (typ *Type) Funcs() []*Func Funcs lists the funcs related to the type. This only includes functions which return an instance of the type or its pointer. + ### func \(\*Type\) [Level]() ```go @@ -715,6 +1124,7 @@ func (typ *Type) Level() int Level provides the default level that headers for the type should be rendered. + ### func \(\*Type\) [Location]() ```go @@ -723,6 +1133,7 @@ func (typ *Type) Location() Location Location returns a representation of the node's location in a file within a repository. + ### func \(\*Type\) [Methods]() ```go @@ -731,6 +1142,7 @@ func (typ *Type) Methods() []*Func Methods lists the funcs that use the type as a value or pointer receiver. + ### func \(\*Type\) [Name]() ```go @@ -739,6 +1151,7 @@ func (typ *Type) Name() string Name provides the name of the type + ### func \(\*Type\) [Summary]() ```go @@ -747,6 +1160,7 @@ func (typ *Type) Summary() string Summary provides the one\-sentence summary of the type's documentation comment. + ### func \(\*Type\) [Title]() ```go @@ -755,6 +1169,7 @@ func (typ *Type) Title() string Title provides a formatted name suitable for use in a header identifying the type. + ### func \(\*Type\) [Vars]() ```go @@ -763,6 +1178,7 @@ func (typ *Type) Vars() []*Value Vars lists the var declaration blocks containing values of this type. + ## type [Value]() Value holds documentation for a var or const declaration within a package. @@ -773,6 +1189,7 @@ type Value struct { } ``` + ### func [NewValue]() ```go @@ -781,6 +1198,16 @@ func NewValue(cfg *Config, doc *doc.Value) *Value NewValue creates a new Value from the raw const or var documentation and the token.FileSet of files for the containing package. + +### func \(\*Value\) [Anchor]() + +```go +func (v *Value) Anchor() string +``` + +Anchor produces anchor text for the value. + + ### func \(\*Value\) [Decl]() ```go @@ -789,6 +1216,7 @@ func (v *Value) Decl() (string, error) Decl provides the raw text representation of the code for declaring the const or var. + ### func \(\*Value\) [Doc]() ```go @@ -797,6 +1225,7 @@ func (v *Value) Doc() *Doc Doc provides the structured contents of the documentation comment for the example. + ### func \(\*Value\) [Level]() ```go @@ -805,6 +1234,7 @@ func (v *Value) Level() int Level provides the default level that headers for the value should be rendered. + ### func \(\*Value\) [Location]() ```go @@ -813,6 +1243,7 @@ func (v *Value) Location() Location Location returns a representation of the node's location in a file within a repository. + ### func \(\*Value\) [Summary]() ```go @@ -821,6 +1252,4 @@ func (v *Value) Summary() string Summary provides the one\-sentence summary of the value's documentation comment. - - Generated by [gomarkdoc]() diff --git a/lang/block.go b/lang/block.go index b9a8390..4ce4c73 100644 --- a/lang/block.go +++ b/lang/block.go @@ -1,12 +1,19 @@ package lang +import ( + "go/doc/comment" + "strings" +) + type ( // Block defines a single block element (e.g. paragraph, code block) in the // documentation for a symbol or package. Block struct { - cfg *Config - kind BlockKind - text string + cfg *Config + kind BlockKind + spans []*Span + list *List + inline bool } // BlockKind identifies the type of block element represented by the @@ -23,12 +30,23 @@ const ( // HeaderBlock defines a block that represents a section header. HeaderBlock BlockKind = "header" + + // ListBlock defines a block that represents an ordered or unordered list. + ListBlock BlockKind = "list" ) // NewBlock creates a new block element of the provided kind and with the given -// text contents. -func NewBlock(cfg *Config, kind BlockKind, text string) *Block { - return &Block{cfg, kind, text} +// text spans and a flag indicating whether this block is part of an inline +// element. +func NewBlock(cfg *Config, kind BlockKind, spans []*Span, inline bool) *Block { + return &Block{cfg, kind, spans, nil, inline} +} + +// NewListBlock creates a new list block element and with the given list +// definition and a flag indicating whether this block is part of an inline +// element. +func NewListBlock(cfg *Config, list *List, inline bool) *Block { + return &Block{cfg, ListBlock, nil, list, inline} } // Level provides the default level that a block of kind HeaderBlock will render @@ -43,9 +61,51 @@ func (b *Block) Kind() BlockKind { return b.kind } -// Text provides the raw text of the block's contents. The text is pre-scrubbed -// and sanitized as determined by the block's Kind(), but it is not wrapped in -// any special constructs for rendering purposes (such as markdown code blocks). -func (b *Block) Text() string { - return b.text +// Spans provides the raw text of the block's contents as a set of text spans. +// The text is pre-scrubbed and sanitized as determined by the block's Kind(), +// but it is not wrapped in any special constructs for rendering purposes (such +// as markdown code blocks). +func (b *Block) Spans() []*Span { + return b.spans +} + +// List provides the list contents for a list block. Only relevant for blocks of +// type ListBlock. +func (b *Block) List() *List { + return b.list +} + +// Inline indicates whether the block is part of an inline element, such as a +// list item. +func (b *Block) Inline() bool { + return b.inline +} + +// ParseBlocks produces a set of blocks from the corresponding comment blocks. +// It also takes a flag indicating whether the blocks are part of an inline +// element such as a list item. +func ParseBlocks(cfg *Config, blocks []comment.Block, inline bool) []*Block { + res := make([]*Block, len(blocks)) + for i, b := range blocks { + switch v := b.(type) { + case *comment.Code: + res[i] = NewBlock( + cfg.Inc(0), + CodeBlock, + []*Span{NewSpan(cfg.Inc(0), RawTextSpan, v.Text, "")}, + inline, + ) + case *comment.Heading: + var b strings.Builder + printText(&b, v.Text...) + res[i] = NewBlock(cfg.Inc(0), HeaderBlock, ParseSpans(cfg, v.Text), inline) + case *comment.List: + list := NewList(cfg.Inc(0), v) + res[i] = NewListBlock(cfg.Inc(0), list, inline) + case *comment.Paragraph: + res[i] = NewBlock(cfg.Inc(0), ParagraphBlock, ParseSpans(cfg, v.Text), inline) + } + } + + return res } diff --git a/lang/config.go b/lang/config.go index b79e221..20ae932 100644 --- a/lang/config.go +++ b/lang/config.go @@ -4,8 +4,13 @@ import ( "errors" "fmt" "go/ast" + "go/doc" + "go/parser" "go/token" "io" + "io/ioutil" + "os" + "path" "path/filepath" "regexp" "strings" @@ -19,10 +24,13 @@ type ( // a construct. Config struct { FileSet *token.FileSet + Files []*ast.File Level int Repo *Repo PkgDir string WorkDir string + Symbols map[string]Symbol + Pkg *doc.Package Log logger.Logger } @@ -83,6 +91,13 @@ func NewConfig(log logger.Logger, workDir string, pkgDir string, opts ...ConfigO return nil, err } + files, err := parsePkgFiles(pkgDir, cfg.FileSet) + if err != nil { + return nil, err + } + + cfg.Files = files + if cfg.Repo == nil || cfg.Repo.Remote == "" || cfg.Repo.DefaultBranch == "" || cfg.Repo.PathFromRoot == "" { repo, err := getRepoForDir(log, cfg.WorkDir, cfg.PkgDir, cfg.Repo) if err != nil { @@ -109,10 +124,13 @@ func NewConfig(log logger.Logger, workDir string, pkgDir string, opts ...ConfigO func (c *Config) Inc(step int) *Config { return &Config{ FileSet: c.FileSet, + Files: c.Files, Level: c.Level + step, PkgDir: c.PkgDir, WorkDir: c.WorkDir, Repo: c.Repo, + Symbols: c.Symbols, + Pkg: c.Pkg, Log: c.Log, } } @@ -352,3 +370,33 @@ func NewLocation(cfg *Config, node ast.Node) Location { Repo: cfg.Repo, } } + +func parsePkgFiles(pkgDir string, fs *token.FileSet) ([]*ast.File, error) { + rawFiles, err := ioutil.ReadDir(pkgDir) + if err != nil { + return nil, fmt.Errorf("gomarkdoc: error reading package dir: %w", err) + } + + var files []*ast.File + for _, f := range rawFiles { + if !strings.HasSuffix(f.Name(), ".go") && !strings.HasSuffix(f.Name(), ".cgo") { + continue + } + + p := path.Join(pkgDir, f.Name()) + + fi, err := os.Stat(p) + if err != nil || !fi.Mode().IsRegular() { + continue + } + + parsed, err := parser.ParseFile(fs, p, nil, parser.ParseComments) + if err != nil { + return nil, fmt.Errorf("gomarkdoc: failed to parse package file %s", f.Name()) + } + + files = append(files, parsed) + } + + return files, nil +} diff --git a/lang/doc.go b/lang/doc.go index 52afca3..c27e13f 100644 --- a/lang/doc.go +++ b/lang/doc.go @@ -1,10 +1,5 @@ package lang -import ( - "regexp" - "strings" -) - // Doc provides access to the documentation comment contents for a package or // symbol in a structured form. type Doc struct { @@ -12,49 +7,17 @@ type Doc struct { blocks []*Block } -var ( - multilineRegex = regexp.MustCompile("\n(?:[\t\f ]*\n)+") - headerRegex = regexp.MustCompile(`^[A-Z][^!:;,{}\[\]<>.?]*\n(?:[\t\f ]*\n)`) - spaceCodeBlockRegex = regexp.MustCompile(`^(?:(?:(?:(?: ).*[^\s]+.*)|[\t\f ]*)\n)+`) - tabCodeBlockRegex = regexp.MustCompile(`^(?:(?:(?:\t.*[^\s]+.*)|[\t\f ]*)\n)+`) - blankLineRegex = regexp.MustCompile(`^[\t\f ]*\n`) -) - // NewDoc initializes a Doc struct from the provided raw documentation text and // with headers rendered by default at the heading level provided. Documentation // is separated into block level elements using the standard rules from golang's // documentation conventions. func NewDoc(cfg *Config, text string) *Doc { // Replace CRLF with LF - rawText := []byte(normalizeDoc(text) + "\n") - - var blocks []*Block - for len(rawText) > 0 { - // Blank lines (ignore) - if l, ok := parseBlankLine(rawText); ok { - rawText = rawText[l:] - continue - } + rawText := normalizeDoc(text) - // Header - if b, l, ok := parseHeaderBlock(cfg, rawText); ok { - blocks = append(blocks, b) - rawText = rawText[l:] - continue - } + parsed := cfg.Pkg.Parser().Parse(rawText) - // Code block - if b, l, ok := parseCodeBlock(cfg, rawText); ok { - blocks = append(blocks, b) - rawText = rawText[l:] - continue - } - - // Paragraph - b, l := parseParagraph(cfg, rawText) - blocks = append(blocks, b) - rawText = rawText[l:] - } + blocks := ParseBlocks(cfg, parsed.Content, false) return &Doc{cfg, blocks} } @@ -70,82 +33,3 @@ func (d *Doc) Level() int { func (d *Doc) Blocks() []*Block { return d.blocks } - -func parseBlankLine(text []byte) (length int, ok bool) { - if l := blankLineRegex.Find(text); l != nil { - // Ignore blank lines - return len(l), true - } - - return 0, false -} - -func parseHeaderBlock(cfg *Config, text []byte) (block *Block, length int, ok bool) { - if l := headerRegex.Find(text); l != nil { - headerText := strings.TrimSpace(string(l)) - return NewBlock(cfg.Inc(0), HeaderBlock, headerText), len(l), true - } - - return nil, 0, false -} - -func parseCodeBlock(cfg *Config, text []byte) (block *Block, length int, ok bool) { - l := spaceCodeBlockRegex.Find(text) - var indent rune - if l != nil { - indent = ' ' - } else { - l = tabCodeBlockRegex.Find(text) - if l != nil { - indent = '\t' - } else { - return nil, 0, false - } - } - - lines := strings.Split(string(l), "\n") - - minIndent := -1 - for _, line := range lines { - for i, r := range line { - if r != indent && (minIndent == -1 || i < minIndent) { - minIndent = i - } - } - } - - var trimmedBlock strings.Builder - for i, line := range lines { - if i > 0 { - trimmedBlock.WriteRune('\n') - } - - if len(strings.TrimSpace(line)) > 0 { - trimmedBlock.WriteString(line[minIndent:]) - } - } - - return NewBlock(cfg.Inc(0), CodeBlock, trimmedBlock.String()), len(l), true -} - -func parseParagraph(cfg *Config, text []byte) (block *Block, length int) { - if loc := multilineRegex.FindIndex(text); loc != nil { - // Paragraph followed by something else - paragraph := strings.TrimSpace(string(text[:loc[1]])) - return NewBlock(cfg.Inc(0), ParagraphBlock, formatDocParagraph(paragraph)), loc[1] - } - - // Last paragraph - paragraph := strings.TrimSpace(string(text)) - - var mergedParagraph strings.Builder - for i, line := range strings.Split(paragraph, "\n") { - if i > 0 { - mergedParagraph.WriteRune(' ') - } - - mergedParagraph.WriteString(strings.TrimSpace(line)) - } - - return NewBlock(cfg.Inc(0), ParagraphBlock, mergedParagraph.String()), len(text) -} diff --git a/lang/example.go b/lang/example.go index 04a0569..3d7d94c 100644 --- a/lang/example.go +++ b/lang/example.go @@ -3,7 +3,7 @@ package lang import ( "fmt" "go/doc" - "go/format" + "go/printer" "strings" ) @@ -67,15 +67,27 @@ func (ex *Example) Code() (string, error) { if ex.doc.Play != nil { codeNode = ex.doc.Play } else { - codeNode = ex.doc.Code + codeNode = &printer.CommentedNode{Node: ex.doc.Code, Comments: ex.doc.Comments} } var code strings.Builder - if err := format.Node(&code, ex.cfg.FileSet, codeNode); err != nil { + p := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8} + err := p.Fprint(&code, ex.cfg.FileSet, codeNode) + if err != nil { return "", err } - return code.String(), nil + str := code.String() + + // additional formatting if this is a function body + if i := len(str); i >= 2 && str[0] == '{' && str[i-1] == '}' { + // remove surrounding braces + str = str[1 : i-1] + // unindent + str = strings.ReplaceAll(str, "\n\t", "\n") + } + + return str, nil } // Output provides the code's example output. diff --git a/lang/func.go b/lang/func.go index 0a7c372..ea6f5b7 100644 --- a/lang/func.go +++ b/lang/func.go @@ -103,6 +103,22 @@ func (fn *Func) Examples() (examples []*Example) { return } +// Anchor produces anchor text for the func. +func (fn *Func) Anchor() string { + if fn.doc.Recv != "" { + return Symbol{ + Kind: MethodSymbolKind, + Receiver: fn.doc.Recv, + Name: fn.doc.Name, + }.Anchor() + } + + return Symbol{ + Kind: FuncSymbolKind, + Name: fn.doc.Name, + }.Anchor() +} + func (fn *Func) rawRecv() string { // remove type parameters recv := strings.Split(fn.doc.Recv, "[")[0] diff --git a/lang/func_test.go b/lang/func_test.go index e7d80bb..bf83445 100644 --- a/lang/func_test.go +++ b/lang/func_test.go @@ -73,37 +73,6 @@ func TestFunc_Receiver_receiver(t *testing.T) { is.Equal(fn.Receiver(), "Receiver") } -func TestFunc_Doc(t *testing.T) { - is := is.New(t) - - fn, err := loadFunc("../testData/lang/function", "Standalone") - is.NoErr(err) - - doc := fn.Doc() - blocks := doc.Blocks() - is.Equal(len(blocks), 5) - - is.Equal(blocks[0].Kind(), lang.ParagraphBlock) - is.Equal(blocks[0].Level(), 3) - is.Equal(blocks[0].Text(), "Standalone provides a function that is not part of a type.") - - is.Equal(blocks[1].Kind(), lang.ParagraphBlock) - is.Equal(blocks[1].Level(), 3) - is.Equal(blocks[1].Text(), "Additional description can be provided in subsequent paragraphs, including code blocks and headers") - - is.Equal(blocks[2].Kind(), lang.HeaderBlock) - is.Equal(blocks[2].Level(), 3) - is.Equal(blocks[2].Text(), "Header A") - - is.Equal(blocks[3].Kind(), lang.ParagraphBlock) - is.Equal(blocks[3].Level(), 3) - is.Equal(blocks[3].Text(), "This section contains a code block.") - - is.Equal(blocks[4].Kind(), lang.CodeBlock) - is.Equal(blocks[4].Level(), 3) - is.Equal(blocks[4].Text(), "Code Block\nMore of Code Block\n") -} - func TestFunc_Location(t *testing.T) { is := is.New(t) diff --git a/lang/list.go b/lang/list.go new file mode 100644 index 0000000..6d4f0de --- /dev/null +++ b/lang/list.go @@ -0,0 +1,92 @@ +package lang + +import ( + "go/doc/comment" + "strconv" +) + +// List defines a list block element in the documentation for a symbol or +// package. +type List struct { + blankBetween bool + items []*Item +} + +// NewList initializes a list from the equivalent type from the comment package. +func NewList(cfg *Config, docList *comment.List) *List { + var l List + l.items = make([]*Item, len(docList.Items)) + for i, item := range docList.Items { + l.items[i] = NewItem(cfg.Inc(0), item) + } + + l.blankBetween = docList.BlankBetween() + + return &l +} + +// BlankBetween returns true if there should be a blank line between list items. +func (l *List) BlankBetween() bool { + return l.blankBetween +} + +// Items returns the slice of items in the list. +func (l *List) Items() []*Item { + return l.items +} + +// ItemKind identifies the kind of item +type ItemKind string + +const ( + // OrderedItem identifies an ordered (i.e. numbered) item. + OrderedItem ItemKind = "ordered" + + // UnorderedItem identifies an unordered (i.e. bulletted) item. + UnorderedItem ItemKind = "unordered" +) + +// Item defines a single item in a list in the documentation for a symbol or +// package. +type Item struct { + blocks []*Block + kind ItemKind + number int +} + +// NewItem initializes a list item from the equivalent type from the comment +// package. +func NewItem(cfg *Config, docItem *comment.ListItem) *Item { + var ( + num int + kind ItemKind + ) + if n, err := strconv.Atoi(docItem.Number); err == nil { + num = n + kind = OrderedItem + } else { + kind = UnorderedItem + } + + return &Item{ + blocks: ParseBlocks(cfg, docItem.Content, true), + kind: kind, + number: num, + } +} + +// Blocks returns the blocks of documentation in a list item. +func (i *Item) Blocks() []*Block { + return i.blocks +} + +// Kind returns the kind of the list item. +func (i *Item) Kind() ItemKind { + return i.kind +} + +// Number returns the number of the list item. Only populated if the item is of +// the OrderedItem kind. +func (i *Item) Number() int { + return i.number +} diff --git a/lang/package.go b/lang/package.go index c958039..09f5906 100644 --- a/lang/package.go +++ b/lang/package.go @@ -41,8 +41,8 @@ type ( // raw documentation constructs provided by the standard library. This is only // recommended for advanced scenarios. Most consumers will find it easier to use // NewPackageFromBuild instead. -func NewPackage(cfg *Config, doc *doc.Package, examples []*doc.Example) *Package { - return &Package{cfg, doc, examples} +func NewPackage(cfg *Config, examples []*doc.Example) *Package { + return &Package{cfg, cfg.Pkg, examples} } // NewPackageFromBuild creates a representation of a package's documentation @@ -66,19 +66,17 @@ func NewPackageFromBuild(log logger.Logger, pkg *build.Package, opts ...PackageO return nil, err } - docPkg, err := getDocPkg(pkg, cfg.FileSet, options.includeUnexported) + cfg.Pkg, err = getDocPkg(pkg, cfg.FileSet, options.includeUnexported) if err != nil { return nil, err } - files, err := parsePkgFiles(pkg, cfg.FileSet) - if err != nil { - return nil, err - } + sym := PackageSymbols(cfg.Pkg) + cfg.Symbols = sym - examples := doc.Examples(files...) + examples := doc.Examples(cfg.Files...) - return NewPackage(cfg, docPkg, examples), nil + return NewPackage(cfg, examples), nil } // PackageWithUnexportedIncluded can be used along with the NewPackageFromBuild @@ -329,33 +327,3 @@ func getDocPkg(pkg *build.Package, fs *token.FileSet, includeUnexported bool) (* return doc.New(astPkg, importPath, doc.AllDecls), nil } - -func parsePkgFiles(pkg *build.Package, fs *token.FileSet) ([]*ast.File, error) { - rawFiles, err := ioutil.ReadDir(pkg.Dir) - if err != nil { - return nil, fmt.Errorf("gomarkdoc: error reading package dir: %w", err) - } - - var files []*ast.File - for _, f := range rawFiles { - if !strings.HasSuffix(f.Name(), ".go") && !strings.HasSuffix(f.Name(), ".cgo") { - continue - } - - p := path.Join(pkg.Dir, f.Name()) - - fi, err := os.Stat(p) - if err != nil || !fi.Mode().IsRegular() { - continue - } - - parsed, err := parser.ParseFile(fs, p, nil, parser.ParseComments) - if err != nil { - return nil, fmt.Errorf("gomarkdoc: failed to parse package file %s", f.Name()) - } - - files = append(files, parsed) - } - - return files, nil -} diff --git a/lang/span.go b/lang/span.go new file mode 100644 index 0000000..f09d011 --- /dev/null +++ b/lang/span.go @@ -0,0 +1,138 @@ +package lang + +import ( + "fmt" + "go/doc/comment" + "regexp" + "strings" +) + +type ( + // Span defines a single text span in a block for documentation of a symbol + // or package. + Span struct { + cfg *Config + kind SpanKind + text string + url string + } + + // SpanKind identifies the type of span element represented by the + // corresponding Span. + SpanKind string +) + +const ( + // TextSpan defines a span that represents plain text. + TextSpan SpanKind = "text" + + // RawTextSpan defines a span that represents plain text that should be + // displayed as-is. + RawTextSpan SpanKind = "rawText" + + // LinkSpan defines a span that represents a link. + LinkSpan SpanKind = "link" + + // AutolinkSpan defines a span that represents text which is itself a link. + AutolinkSpan SpanKind = "autolink" +) + +// NewSpan creates a new span. +func NewSpan(cfg *Config, kind SpanKind, text string, url string) *Span { + return &Span{cfg, kind, text, url} +} + +// Kind provides the kind of data that this span represents. +func (s *Span) Kind() SpanKind { + return s.kind +} + +// Text provides the raw text for the span. +func (s *Span) Text() string { + return s.text +} + +// URL provides the url associated with the span, if any. +func (s *Span) URL() string { + return s.url +} + +// ParseSpans turns a set of *comment.Text entries into a slice of spans. +func ParseSpans(cfg *Config, texts []comment.Text) []*Span { + var s []*Span + for _, t := range texts { + switch v := t.(type) { + case comment.Plain: + s = append(s, NewSpan(cfg.Inc(0), TextSpan, collapseWhitespace(string(v)), "")) + case comment.Italic: + s = append(s, NewSpan(cfg.Inc(0), TextSpan, collapseWhitespace(string(v)), "")) + case *comment.DocLink: + var b strings.Builder + printText(&b, v.Text...) + str := collapseWhitespace(b.String()) + + // Replace local links as needed + if v.ImportPath == "" { + name := symbolName(v.Recv, v.Name) + if sym, ok := cfg.Symbols[name]; ok { + s = append(s, NewSpan(cfg.Inc(0), LinkSpan, str, fmt.Sprintf("#%s", sym.Anchor()))) + } else { + cfg.Log.Warnf("Unable to find symbol %s", name) + s = append(s, NewSpan(cfg.Inc(0), TextSpan, collapseWhitespace(str), "")) + } + break + } + + s = append(s, NewSpan(cfg.Inc(0), LinkSpan, str, v.DefaultURL("https://pkg.go.dev/"))) + case *comment.Link: + var b strings.Builder + printText(&b, v.Text...) + str := collapseWhitespace(b.String()) + + if v.Auto { + s = append(s, NewSpan(cfg.Inc(0), AutolinkSpan, str, str)) + break + } + + s = append(s, NewSpan(cfg.Inc(0), LinkSpan, str, v.URL)) + } + } + + return s +} + +func printText(b *strings.Builder, text ...comment.Text) { + for i, t := range text { + if i > 0 { + b.WriteRune(' ') + } + + switch v := t.(type) { + case comment.Plain: + b.WriteString(string(v)) + case comment.Italic: + b.WriteString(string(v)) + case *comment.DocLink: + printText(b, v.Text...) + case *comment.Link: + // No need to linkify implicit links + if v.Auto { + printText(b, v.Text...) + continue + } + + b.WriteRune('[') + printText(b, v.Text...) + b.WriteRune(']') + b.WriteRune('(') + b.WriteString(v.URL) + b.WriteRune(')') + } + } +} + +var whitespaceRegex = regexp.MustCompile(`\s+`) + +func collapseWhitespace(s string) string { + return string(whitespaceRegex.ReplaceAll([]byte(s), []byte(" "))) +} diff --git a/lang/symbol.go b/lang/symbol.go new file mode 100644 index 0000000..bfe7c6c --- /dev/null +++ b/lang/symbol.go @@ -0,0 +1,181 @@ +package lang + +import ( + "fmt" + "go/ast" + "go/doc" + "strings" +) + +type ( + // Symbol provides identity information for a symbol in a package. + Symbol struct { + // Receiver holds the receiver for a method or field. + Receiver string + // Name holds the name of the symbol itself. + Name string + // Kind identifies the category of the symbol. + Kind SymbolKind + // Parent holds the linkable parent symbol which contains this one. + Parent *Symbol + } + + // SymbolKind identifies the type of symbol. + SymbolKind int +) + +// The list of valid symbol kinds. +const ( + TypeSymbolKind SymbolKind = iota + 1 + FuncSymbolKind + ConstSymbolKind + VarSymbolKind + MethodSymbolKind + FieldSymbolKind +) + +// PackageSymbols gets the list of symbols for a doc package. +func PackageSymbols(pkg *doc.Package) map[string]Symbol { + sym := make(map[string]Symbol) + for _, c := range pkg.Consts { + parent := Symbol{ + Name: c.Names[0], + Kind: ConstSymbolKind, + } + + for _, n := range c.Names { + sym[symbolName("", n)] = Symbol{ + Name: n, + Kind: ConstSymbolKind, + Parent: &parent, + } + } + } + + for _, v := range pkg.Vars { + parent := Symbol{ + Name: v.Names[0], + Kind: VarSymbolKind, + } + + for _, n := range v.Names { + sym[symbolName("", n)] = Symbol{ + Name: n, + Kind: VarSymbolKind, + Parent: &parent, + } + } + } + + for _, v := range pkg.Funcs { + sym[symbolName("", v.Name)] = Symbol{ + Name: v.Name, + Kind: FuncSymbolKind, + } + } + + for _, t := range pkg.Types { + typeSymbols(sym, t) + } + + return sym +} + +func typeSymbols(sym map[string]Symbol, t *doc.Type) { + typeSym := Symbol{ + Name: t.Name, + Kind: TypeSymbolKind, + } + + sym[t.Name] = typeSym + + for _, f := range t.Methods { + sym[symbolName(t.Name, f.Name)] = Symbol{ + Receiver: t.Name, + Name: f.Name, + Kind: MethodSymbolKind, + } + } + + for _, s := range t.Decl.Specs { + typ, ok := s.(*ast.TypeSpec).Type.(*ast.StructType) + if !ok { + continue + } + + for _, f := range typ.Fields.List { + for _, n := range f.Names { + sym[symbolName(t.Name, n.String())] = Symbol{ + Receiver: t.Name, + Name: n.String(), + Kind: FieldSymbolKind, + Parent: &typeSym, + } + } + } + } + + for _, f := range t.Funcs { + sym[symbolName("", f.Name)] = Symbol{ + Name: f.Name, + Kind: FuncSymbolKind, + } + } + + for _, c := range t.Consts { + parent := Symbol{ + Name: c.Names[0], + Kind: ConstSymbolKind, + } + + for _, n := range c.Names { + sym[symbolName("", n)] = Symbol{ + Name: n, + Kind: ConstSymbolKind, + Parent: &parent, + } + } + } + + for _, v := range t.Vars { + parent := Symbol{ + Name: v.Names[0], + Kind: VarSymbolKind, + } + + for _, n := range v.Names { + sym[symbolName("", n)] = Symbol{ + Name: n, + Kind: VarSymbolKind, + Parent: &parent, + } + } + } + +} + +// Anchor produces anchor text for the symbol. +func (s Symbol) Anchor() string { + if s.Parent != nil { + return s.Parent.Anchor() + } + + switch s.Kind { + case MethodSymbolKind, FieldSymbolKind: + return fmt.Sprintf("%s.%s", strings.TrimLeft(s.Receiver, "*"), s.Name) + default: + return s.Name + } +} + +// symbolName returns the string representation of the symbol. +func symbolName(receiver string, name string) string { + receiver = strings.TrimLeft(receiver, "*") + name = strings.TrimLeft(name, "*") + + if receiver == "" { + return name + } + + return fmt.Sprintf("%s.%s", receiver, name) +} diff --git a/lang/type.go b/lang/type.go index c0a8a8c..2415278 100644 --- a/lang/type.go +++ b/lang/type.go @@ -135,3 +135,11 @@ func (typ *Type) Vars() []*Value { return vars } + +// Anchor produces anchor text for the type. +func (typ *Type) Anchor() string { + return Symbol{ + Kind: TypeSymbolKind, + Name: typ.doc.Name, + }.Anchor() +} diff --git a/lang/type_test.go b/lang/type_test.go index 7667769..d3af3fb 100644 --- a/lang/type_test.go +++ b/lang/type_test.go @@ -22,224 +22,6 @@ func TestType_Examples(t *testing.T) { is.Equal(ex[1].Name(), "Sub Test") } -func TestFunc_netHttpResponseWriter(t *testing.T) { - is := is.New(t) - - buildPkg, err := getBuildPackage("net/http") - is.NoErr(err) - - log := logger.New(logger.ErrorLevel) - pkg, err := lang.NewPackageFromBuild(log, buildPkg) - is.NoErr(err) - - var typ *lang.Type - for _, t := range pkg.Types() { - if t.Name() == "ResponseWriter" { - typ = t - break - } - } - - is.True(typ != nil) // didn't find the type we were looking for - - decl, err := typ.Decl() - is.NoErr(err) - - is.Equal(typ.Level(), 2) - is.Equal(typ.Name(), "ResponseWriter") - is.Equal(typ.Title(), "type ResponseWriter") - is.Equal(typ.Summary(), "A ResponseWriter interface is used by an HTTP handler to construct an HTTP response.") - is.Equal(decl, `type ResponseWriter interface { - // Header returns the header map that will be sent by - // WriteHeader. The Header map also is the mechanism with which - // Handlers can set HTTP trailers. - // - // Changing the header map after a call to WriteHeader (or - // Write) has no effect unless the HTTP status code was of the - // 1xx class or the modified headers are trailers. - // - // There are two ways to set Trailers. The preferred way is to - // predeclare in the headers which trailers you will later - // send by setting the "Trailer" header to the names of the - // trailer keys which will come later. In this case, those - // keys of the Header map are treated as if they were - // trailers. See the example. The second way, for trailer - // keys not known to the Handler until after the first Write, - // is to prefix the Header map keys with the TrailerPrefix - // constant value. See TrailerPrefix. - // - // To suppress automatic response headers (such as "Date"), set - // their value to nil. - Header() Header - - // Write writes the data to the connection as part of an HTTP reply. - // - // If WriteHeader has not yet been called, Write calls - // WriteHeader(http.StatusOK) before writing the data. If the Header - // does not contain a Content-Type line, Write adds a Content-Type set - // to the result of passing the initial 512 bytes of written data to - // DetectContentType. Additionally, if the total size of all written - // data is under a few KB and there are no Flush calls, the - // Content-Length header is added automatically. - // - // Depending on the HTTP protocol version and the client, calling - // Write or WriteHeader may prevent future reads on the - // Request.Body. For HTTP/1.x requests, handlers should read any - // needed request body data before writing the response. Once the - // headers have been flushed (due to either an explicit Flusher.Flush - // call or writing enough data to trigger a flush), the request body - // may be unavailable. For HTTP/2 requests, the Go HTTP server permits - // handlers to continue to read the request body while concurrently - // writing the response. However, such behavior may not be supported - // by all HTTP/2 clients. Handlers should read before writing if - // possible to maximize compatibility. - Write([]byte) (int, error) - - // WriteHeader sends an HTTP response header with the provided - // status code. - // - // If WriteHeader is not called explicitly, the first call to Write - // will trigger an implicit WriteHeader(http.StatusOK). - // Thus explicit calls to WriteHeader are mainly used to - // send error codes or 1xx informational responses. - // - // The provided code must be a valid HTTP 1xx-5xx status code. - // Any number of 1xx headers may be written, followed by at most - // one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx - // headers may be buffered. Use the Flusher interface to send - // buffered data. The header map is cleared when 2xx-5xx headers are - // sent, but not with 1xx headers. - // - // The server will automatically send a 100 (Continue) header - // on the first read from the request body if the request has - // an "Expect: 100-continue" header. - WriteHeader(statusCode int) -}`) - is.Equal(len(typ.Examples()), 1) - is.Equal(len(typ.Funcs()), 0) - is.Equal(len(typ.Methods()), 0) -} - -func TestFunc_netHttpResponse(t *testing.T) { - is := is.New(t) - - buildPkg, err := getBuildPackage("net/http") - is.NoErr(err) - - log := logger.New(logger.ErrorLevel) - pkg, err := lang.NewPackageFromBuild(log, buildPkg) - is.NoErr(err) - - var typ *lang.Type - for _, t := range pkg.Types() { - if t.Name() == "Response" { - typ = t - break - } - } - - is.True(typ != nil) // didn't find the type we were looking for - - decl, err := typ.Decl() - is.NoErr(err) - - is.Equal(typ.Level(), 2) - is.Equal(typ.Name(), "Response") - is.Equal(typ.Title(), "type Response") - is.Equal(typ.Summary(), "Response represents the response from an HTTP request.") - is.Equal(decl, `type Response struct { - Status string // e.g. "200 OK" - StatusCode int // e.g. 200 - Proto string // e.g. "HTTP/1.0" - ProtoMajor int // e.g. 1 - ProtoMinor int // e.g. 0 - - // Header maps header keys to values. If the response had multiple - // headers with the same key, they may be concatenated, with comma - // delimiters. (RFC 7230, section 3.2.2 requires that multiple headers - // be semantically equivalent to a comma-delimited sequence.) When - // Header values are duplicated by other fields in this struct (e.g., - // ContentLength, TransferEncoding, Trailer), the field values are - // authoritative. - // - // Keys in the map are canonicalized (see CanonicalHeaderKey). - Header Header - - // Body represents the response body. - // - // The response body is streamed on demand as the Body field - // is read. If the network connection fails or the server - // terminates the response, Body.Read calls return an error. - // - // The http Client and Transport guarantee that Body is always - // non-nil, even on responses without a body or responses with - // a zero-length body. It is the caller's responsibility to - // close Body. The default HTTP client's Transport may not - // reuse HTTP/1.x "keep-alive" TCP connections if the Body is - // not read to completion and closed. - // - // The Body is automatically dechunked if the server replied - // with a "chunked" Transfer-Encoding. - // - // As of Go 1.12, the Body will also implement io.Writer - // on a successful "101 Switching Protocols" response, - // as used by WebSockets and HTTP/2's "h2c" mode. - Body io.ReadCloser - - // ContentLength records the length of the associated content. The - // value -1 indicates that the length is unknown. Unless Request.Method - // is "HEAD", values >= 0 indicate that the given number of bytes may - // be read from Body. - ContentLength int64 - - // Contains transfer encodings from outer-most to inner-most. Value is - // nil, means that "identity" encoding is used. - TransferEncoding []string - - // Close records whether the header directed that the connection be - // closed after reading Body. The value is advice for clients: neither - // ReadResponse nor Response.Write ever closes a connection. - Close bool - - // Uncompressed reports whether the response was sent compressed but - // was decompressed by the http package. When true, reading from - // Body yields the uncompressed content instead of the compressed - // content actually set from the server, ContentLength is set to -1, - // and the "Content-Length" and "Content-Encoding" fields are deleted - // from the responseHeader. To get the original response from - // the server, set Transport.DisableCompression to true. - Uncompressed bool - - // Trailer maps trailer keys to values in the same - // format as Header. - // - // The Trailer initially contains only nil values, one for - // each key specified in the server's "Trailer" header - // value. Those values are not added to Header. - // - // Trailer must not be accessed concurrently with Read calls - // on the Body. - // - // After Body.Read has returned io.EOF, Trailer will contain - // any trailer values sent by the server. - Trailer Header - - // Request is the request that was sent to obtain this Response. - // Request's Body is nil (having already been consumed). - // This is only populated for Client requests. - Request *Request - - // TLS contains information about the TLS connection on which the - // response was received. It is nil for unencrypted responses. - // The pointer is shared between responses and should not be - // modified. - TLS *tls.ConnectionState -}`) - is.Equal(len(typ.Examples()), 0) - is.True(len(typ.Funcs()) > 0) - is.True(len(typ.Methods()) > 0) -} - func loadType(dir, name string) (*lang.Type, error) { buildPkg, err := getBuildPackage(dir) if err != nil { diff --git a/lang/value.go b/lang/value.go index 9c4e3dd..d22451c 100644 --- a/lang/value.go +++ b/lang/value.go @@ -45,3 +45,18 @@ func (v *Value) Doc() *Doc { func (v *Value) Decl() (string, error) { return printNode(v.doc.Decl, v.cfg.FileSet) } + +// Anchor produces anchor text for the value. +func (v *Value) Anchor() string { + var kind SymbolKind + if v.doc.Decl.Tok.String() == "const" { + kind = ConstSymbolKind + } else { + kind = VarSymbolKind + } + + return Symbol{ + Kind: kind, + Name: v.doc.Names[0], + }.Anchor() +} diff --git a/lang/value_test.go b/lang/value_test.go index 97e6635..bc23a1b 100644 --- a/lang/value_test.go +++ b/lang/value_test.go @@ -28,20 +28,6 @@ func TestValue_Summary(t *testing.T) { is.Equal(val.Summary(), "Variable is a package-level variable.") } -func TestValue_Doc(t *testing.T) { - is := is.New(t) - - val, err := loadValue("../testData/lang/function", "Variable") - is.NoErr(err) - - doc := val.Doc() - is.Equal(doc.Level(), 3) - is.Equal(len(doc.Blocks()), 1) - is.Equal(doc.Blocks()[0].Kind(), lang.ParagraphBlock) - is.Equal(doc.Blocks()[0].Level(), 3) - is.Equal(doc.Blocks()[0].Text(), "Variable is a package-level variable.") -} - func TestValue_Decl(t *testing.T) { is := is.New(t) diff --git a/logger/README.md b/logger/README.md new file mode 100644 index 0000000..ec3f250 --- /dev/null +++ b/logger/README.md @@ -0,0 +1,85 @@ + + +# logger + +```go +import "github.com/princjef/gomarkdoc/logger" +``` + +Package logger provides a simple console logger for reporting information about execution to stderr. + +## Index + +- [type Level](<#Level>) +- [type Logger](<#Logger>) + - [func New\(level Level, opts ...Option\) Logger](<#New>) +- [type Option](<#Option>) + - [func WithField\(key string, value interface\{\}\) Option](<#WithField>) + + + +## type [Level]() + +Level defines valid logging levels for a Logger. + +```go +type Level int +``` + +Valid logging levels + +```go +const ( + DebugLevel Level = iota + 1 + InfoLevel + WarnLevel + ErrorLevel +) +``` + + +## type [Logger]() + +Logger provides basic logging capabilities at different logging levels. + +```go +type Logger interface { + Debug(a ...interface{}) + Debugf(format string, a ...interface{}) + Info(a ...interface{}) + Infof(format string, a ...interface{}) + Warn(a ...interface{}) + Warnf(format string, a ...interface{}) + Error(a ...interface{}) + Errorf(format string, a ...interface{}) +} +``` + + +### func [New]() + +```go +func New(level Level, opts ...Option) Logger +``` + +New initializes a new Logger. + + +## type [Option]() + +Option defines an option for configuring the logger. + +```go +type Option func(opts *options) +``` + + +### func [WithField]() + +```go +func WithField(key string, value interface{}) Option +``` + +WithField sets the provided key/value pair for use on all logs. + +Generated by [gomarkdoc]() diff --git a/logger/logger.go b/logger/logger.go index c647a57..fa6dd58 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,3 +1,5 @@ +// Package logger provides a simple console logger for reporting information +// about execution to stderr. package logger import ( diff --git a/magefile.go b/magefile.go index b506636..ac15d59 100644 --- a/magefile.go +++ b/magefile.go @@ -13,7 +13,7 @@ import ( var linter = bintool.Must(bintool.New( "golangci-lint{{.BinExt}}", - "1.45.2", + "1.51.1", "https://github.com/golangci/golangci-lint/releases/download/v{{.Version}}/golangci-lint-{{.Version}}-{{.GOOS}}-{{.GOARCH}}{{.ArchiveExt}}", )) @@ -22,7 +22,7 @@ func Lint() error { return err } - return linter.Command(`run`).Run() + return linter.Command(`run --timeout 5m`).Run() } func Generate() error { @@ -36,18 +36,14 @@ func Build() error { func Doc() error { return shellcmd.RunAll( `go run ./cmd/gomarkdoc .`, - `go run ./cmd/gomarkdoc --header "" ./lang/...`, - `go run ./cmd/gomarkdoc --header "" ./format/...`, - `go run ./cmd/gomarkdoc --header "" ./cmd/...`, + `go run ./cmd/gomarkdoc --header "" --exclude-dirs . --exclude-dirs ./testData/... ./...`, ) } func DocVerify() error { return shellcmd.RunAll( `go run ./cmd/gomarkdoc -c .`, - `go run ./cmd/gomarkdoc -c --header "" ./lang/...`, - `go run ./cmd/gomarkdoc -c --header "" ./format/...`, - `go run ./cmd/gomarkdoc -c --header "" ./cmd/...`, + `go run ./cmd/gomarkdoc -c --header "" --exclude-dirs . --exclude-dirs ./testData/... ./...`, ) } @@ -77,7 +73,7 @@ func RegenerateTestDocs() error { } func Test() error { - return shellcmd.Command(`go test -count 1 -coverprofile=coverage.txt ./...`).Run() + return shellcmd.Command(`go test -count 1 -coverpkg=.,./cmd/...,./format/...,./lang/...,./logger/... -cover -coverprofile=coverage.txt ./...`).Run() } func Coverage() error { diff --git a/renderer.go b/renderer.go index f94eab0..3fb9eec 100644 --- a/renderer.go +++ b/renderer.go @@ -2,6 +2,7 @@ package gomarkdoc import ( "fmt" + "reflect" "strings" "text/template" @@ -16,6 +17,7 @@ type ( templateOverrides map[string]string tmpl *template.Template format format.Format + templateFuncs map[string]any } // RendererOption configures the renderer's behavior. @@ -31,6 +33,7 @@ func NewRenderer(opts ...RendererOption) (*Renderer, error) { renderer := &Renderer{ templateOverrides: make(map[string]string), format: &format.GitHubFlavoredMarkdown{}, + templateFuncs: map[string]any{}, } for _, opt := range opts { @@ -46,29 +49,7 @@ func NewRenderer(opts ...RendererOption) (*Renderer, error) { } if renderer.tmpl == nil { - tmpl := template.New(name) - tmpl.Funcs(map[string]interface{}{ - "add": func(n1, n2 int) int { - return n1 + n2 - }, - "spacer": func() string { - return "\n\n" - }, - - "bold": renderer.format.Bold, - "header": renderer.format.Header, - "rawHeader": renderer.format.RawHeader, - "codeBlock": renderer.format.CodeBlock, - "link": renderer.format.Link, - "listEntry": renderer.format.ListEntry, - "accordion": renderer.format.Accordion, - "accordionHeader": renderer.format.AccordionHeader, - "accordionTerminator": renderer.format.AccordionTerminator, - "localHref": renderer.format.LocalHref, - "codeHref": renderer.format.CodeHref, - "paragraph": renderer.format.Paragraph, - "escape": renderer.format.Escape, - }) + tmpl := renderer.getTemplate(name) if _, err := tmpl.Parse(tmplStr); err != nil { return nil, err @@ -106,6 +87,20 @@ func WithFormat(format format.Format) RendererOption { } } +// WithTemplateFunc adds the provided function with the given name to the list +// of functions that can be used by the rendering templates. +// +// Any name collisions between built-in functions and functions provided here +// are resolved in favor of the function provided here, so be careful about the +// naming of your functions to avoid overriding existing behavior unless +// desired. +func WithTemplateFunc(name string, fn any) RendererOption { + return func(renderer *Renderer) error { + renderer.templateFuncs[name] = fn + return nil + } +} + // File renders a file containing one or more packages to document to a string. // You can change the rendering of the file by overriding the "file" template // or one of the templates it references. @@ -152,3 +147,82 @@ func (out *Renderer) writeTemplate(name string, data interface{}) (string, error return result.String(), nil } + +func (out *Renderer) getTemplate(name string) *template.Template { + tmpl := template.New(name) + + // Capture the base template funcs later because we need them with the right + // format that we got from the options. + baseTemplateFuncs := map[string]any{ + "add": func(n1, n2 int) int { + return n1 + n2 + }, + "spacer": func() string { + return "\n\n" + }, + "inlineSpacer": func() string { + return "\n" + }, + "hangingIndent": func(s string, n int) string { + return strings.ReplaceAll(s, "\n", fmt.Sprintf("\n%s", strings.Repeat(" ", n))) + }, + "include": func(name string, data any) (string, error) { + var b strings.Builder + err := tmpl.ExecuteTemplate(&b, name, data) + if err != nil { + return "", err + } + + return b.String(), nil + }, + "iter": func(l any) (any, error) { + type iter struct { + First bool + Last bool + Entry any + } + + switch reflect.TypeOf(l).Kind() { + case reflect.Slice: + s := reflect.ValueOf(l) + out := make([]iter, s.Len()) + + for i := 0; i < s.Len(); i++ { + out[i] = iter{ + First: i == 0, + Last: i == s.Len()-1, + Entry: s.Index(i).Interface(), + } + } + + return out, nil + default: + return nil, fmt.Errorf("renderer: iter only accepts slices") + } + }, + + "bold": out.format.Bold, + "anchor": out.format.Anchor, + "anchorHeader": out.format.AnchorHeader, + "header": out.format.Header, + "rawAnchorHeader": out.format.RawAnchorHeader, + "rawHeader": out.format.RawHeader, + "codeBlock": out.format.CodeBlock, + "link": out.format.Link, + "listEntry": out.format.ListEntry, + "accordion": out.format.Accordion, + "accordionHeader": out.format.AccordionHeader, + "accordionTerminator": out.format.AccordionTerminator, + "localHref": out.format.LocalHref, + "rawLocalHref": out.format.RawLocalHref, + "codeHref": out.format.CodeHref, + "escape": out.format.Escape, + } + + for n, f := range out.templateFuncs { + baseTemplateFuncs[n] = f + } + + tmpl.Funcs(baseTemplateFuncs) + return tmpl +} diff --git a/renderer_test.go b/renderer_test.go new file mode 100644 index 0000000..19e19bd --- /dev/null +++ b/renderer_test.go @@ -0,0 +1,85 @@ +package gomarkdoc_test + +import ( + "errors" + "go/build" + "os" + "strings" + "testing" + + "github.com/Weborama/gomarkdoc" + "github.com/Weborama/gomarkdoc/format/formatcore" + "github.com/Weborama/gomarkdoc/lang" + "github.com/Weborama/gomarkdoc/logger" + "github.com/matryer/is" +) + +func TestWithTemplateFunc(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("./testData/docs", "Func") + is.NoErr(err) + + r, err := gomarkdoc.NewRenderer() + is.NoErr(err) + + r2, err := gomarkdoc.NewRenderer( + gomarkdoc.WithTemplateFunc("escape", func(text string) string { + return formatcore.Escape(strings.ToUpper(text)) + }), + ) + is.NoErr(err) + + f, err := r.Func(fn) + is.NoErr(err) + + f2, err := r2.Func(fn) + is.NoErr(err) + + is.True(strings.Contains(f, "Func is present in this file.")) + is.True(strings.Contains(f2, "FUNC IS PRESENT IN THIS FILE.")) +} + +func getBuildPackage(path string) (*build.Package, error) { + wd, err := os.Getwd() + if err != nil { + return nil, err + } + + return build.Import(path, wd, build.ImportComment) +} + +func loadFunc(dir, name string) (*lang.Func, error) { + buildPkg, err := getBuildPackage(dir) + if err != nil { + return nil, err + } + + log := logger.New(logger.ErrorLevel) + pkg, err := lang.NewPackageFromBuild(log, buildPkg) + if err != nil { + return nil, err + } + + for _, f := range pkg.Funcs() { + if f.Name() == name { + return f, nil + } + } + + for _, t := range pkg.Types() { + for _, f := range t.Funcs() { + if f.Name() == name { + return f, nil + } + } + + for _, f := range t.Methods() { + if f.Name() == name { + return f, nil + } + } + } + + return nil, errors.New("func not found") +} diff --git a/templates.go b/templates.go index 080c43b..6188737 100644 --- a/templates.go +++ b/templates.go @@ -3,28 +3,35 @@ package gomarkdoc var templates = map[string]string{ - "doc": `{{- range .Blocks -}} - {{- if eq .Kind "paragraph" -}} - {{- paragraph .Text -}} - {{- else if eq .Kind "code" -}} - {{- codeBlock "" .Text -}} - {{- else if eq .Kind "header" -}} - {{- header .Level .Text -}} + "doc": `{{- range (iter .Blocks) -}} + {{- if eq .Entry.Kind "paragraph" -}} + {{- template "text" .Entry.Spans -}} + {{- else if eq .Entry.Kind "code" -}} + {{- codeBlock "" (include "text" .Entry.Spans) -}} + {{- else if eq .Entry.Kind "header" -}} + {{- header .Entry.Level (include "text" .Entry.Spans) -}} + {{- else if eq .Entry.Kind "list" -}} + {{- template "list" .Entry.List -}} {{- end -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} {{- end -}} - `, "example": `{{- accordionHeader .Title -}} +{{- spacer -}} {{- template "doc" .Doc -}} +{{- spacer -}} {{- codeBlock "go" .Code -}} +{{- spacer -}} {{- if .HasOutput -}} {{- header 4 "Output" -}} + {{- spacer -}} {{- codeBlock "" .Output -}} + {{- spacer -}} {{- end -}} @@ -33,154 +40,237 @@ var templates = map[string]string{ `, "file": ` -{{.Header -}} +{{if .Header -}} + {{- .Header -}} + {{- spacer -}} +{{- end -}} {{- range .Packages -}} {{- template "package" . -}} + {{- spacer -}} {{- end -}} -{{- .Footer}} +{{- if .Footer -}} + {{- .Footer -}} + {{- spacer -}} +{{- end -}} Generated by {{link "gomarkdoc" "https://github.com/Weborama/gomarkdoc"}} `, "func": `{{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | rawHeader .Level -}} + {{- rawAnchorHeader .Level (codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver)) .Anchor -}} {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | rawHeader .Level -}} + {{- rawAnchorHeader .Level (codeHref .Location | link (escape .Name) | printf "func %s") .Anchor -}} {{- end -}} +{{- spacer -}} {{- codeBlock "go" .Signature -}} +{{- spacer -}} {{- template "doc" .Doc -}} -{{- range .Examples -}} - {{- template "example" . -}} -{{- end -}} +{{- if len .Examples -}} + {{- spacer -}} -`, - "import": `{{- codeBlock "go" .Import -}} + {{- range (iter .Examples) -}} + {{- template "example" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} +{{- end -}} `, + "import": `{{- codeBlock "go" .Import -}}`, "index": `{{- if len .Consts -}} {{- localHref "Constants" | link "Constants" | listEntry 0 -}} + {{- inlineSpacer -}} {{- end -}} {{- if len .Vars -}} {{- localHref "Variables" | link "Variables" | listEntry 0 -}} + {{- inlineSpacer -}} {{- end -}} {{- range .Funcs -}} - {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | localHref | link .Signature | listEntry 0 -}} - {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | localHref | link .Signature | listEntry 0 -}} - {{- end -}} + {{- (link .Signature (rawLocalHref .Anchor)) | listEntry 0 -}} + {{- inlineSpacer -}} {{- end -}} {{- range .Types -}} - {{- codeHref .Location | link (escape .Name) | printf "type %s" | localHref | link .Title | listEntry 0 -}} + {{- (link .Title (rawLocalHref .Anchor)) | listEntry 0 -}} + {{- inlineSpacer -}} {{- range .Funcs -}} - {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | localHref | link .Signature | listEntry 1 -}} - {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | localHref | link .Signature | listEntry 1 -}} - {{- end -}} + {{- (link .Signature (rawLocalHref .Anchor)) | listEntry 1 -}} + {{- inlineSpacer -}} {{- end -}} {{- range .Methods -}} - {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | localHref | link .Signature | listEntry 1 -}} - {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | localHref | link .Signature | listEntry 1 -}} - {{- end -}} + {{- (link .Signature (rawLocalHref .Anchor)) | listEntry 1 -}} + {{- inlineSpacer -}} {{- end -}} {{- end -}} - -{{- spacer -}} `, + "list": `{{- range (iter .Items) -}} + {{- if eq .Entry.Kind "ordered" -}} + {{- .Entry.Number -}}. {{ hangingIndent (include "doc" .Entry) 2 -}} + {{- else -}} + - {{ hangingIndent (include "doc" .Entry) 2 -}} + {{- end -}} + + {{- if (not .Last) -}} + {{- if $.BlankBetween -}} + {{- spacer -}} + {{- else -}} + {{- inlineSpacer -}} + {{- end -}} + {{- end -}} + +{{- end -}}`, "package": `{{- if eq .Name "main" -}} {{- header .Level .Dirname -}} {{- else -}} {{- header .Level .Name -}} {{- end -}} +{{- spacer -}} {{- template "import" . -}} +{{- spacer -}} -{{- template "doc" .Doc -}} +{{- if len .Doc.Blocks -}} + {{- template "doc" .Doc -}} + {{- spacer -}} +{{- end -}} -{{- range .Examples -}} - {{- template "example" . -}} +{{- range (iter .Examples) -}} + {{- template "example" .Entry -}} + {{- spacer -}} {{- end -}} {{- header (add .Level 1) "Index" -}} +{{- spacer -}} {{- template "index" . -}} {{- if len .Consts -}} + {{- spacer -}} {{- header (add .Level 1) "Constants" -}} + {{- spacer -}} - {{- range .Consts -}} - {{- template "value" . -}} + {{- range (iter .Consts) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} {{- end -}} {{- end -}} {{- if len .Vars -}} + {{- spacer -}} {{- header (add .Level 1) "Variables" -}} + {{- spacer -}} - {{- range .Vars -}} - {{- template "value" . -}} + {{- range (iter .Vars) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} {{- end -}} {{- end -}} -{{- range .Funcs -}} - {{- template "func" . -}} +{{- if len .Funcs -}} + {{- spacer -}} + + {{- range (iter .Funcs) -}} + {{- template "func" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Types -}} - {{- template "type" . -}} +{{- if len .Types -}} + {{- spacer -}} + + {{- range (iter .Types) -}} + {{- template "type" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} `, - "type": `{{- codeHref .Location | link (escape .Name) | printf "type %s" | rawHeader .Level -}} + "text": `{{- range . -}} + {{- if eq .Kind "text" -}} + {{- escape .Text -}} + {{- else if eq .Kind "rawText" -}} + {{- .Text -}} + {{- else if eq .Kind "autolink" -}} + {{- .Text -}} + {{- else if eq .Kind "link" -}} + {{- link (escape .Text) .URL -}} + {{- end -}} +{{- end -}}`, + "type": `{{- rawAnchorHeader .Level (codeHref .Location | link (escape .Name) | printf "type %s") .Anchor -}} +{{- spacer -}} {{- template "doc" .Doc -}} +{{- spacer -}} {{- codeBlock "go" .Decl -}} -{{- range .Consts -}} - {{- template "value" . -}} +{{- if len .Consts -}} + {{- spacer -}} + + {{- range (iter .Consts) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Vars -}} - {{- template "value" . -}} +{{- if len .Vars -}} + {{- spacer -}} + + {{- range (iter .Vars) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Examples -}} - {{- template "example" . -}} +{{- if len .Examples -}} + {{- spacer -}} + + {{- range (iter .Examples) -}} + {{- template "example" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Funcs -}} - {{- template "func" . -}} +{{- if len .Funcs -}} + {{- spacer -}} + + {{- range (iter .Funcs) -}} + {{- template "func" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Methods -}} - {{- template "func" . -}} +{{- if len .Methods -}} + {{- spacer -}} + + {{- range (iter .Methods) -}} + {{- template "func" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} `, - "value": `{{- template "doc" .Doc -}} + "value": `{{- anchor .Anchor -}} +{{- template "doc" .Doc -}} +{{- spacer -}} {{- codeBlock "go" .Decl -}} diff --git a/templates/doc.gotxt b/templates/doc.gotxt index 26765ef..dae9ba2 100644 --- a/templates/doc.gotxt +++ b/templates/doc.gotxt @@ -1,10 +1,12 @@ -{{- range .Blocks -}} - {{- if eq .Kind "paragraph" -}} - {{- paragraph .Text -}} - {{- else if eq .Kind "code" -}} - {{- codeBlock "" .Text -}} - {{- else if eq .Kind "header" -}} - {{- header .Level .Text -}} +{{- range (iter .Blocks) -}} + {{- if eq .Entry.Kind "paragraph" -}} + {{- template "text" .Entry.Spans -}} + {{- else if eq .Entry.Kind "code" -}} + {{- codeBlock "" (include "text" .Entry.Spans) -}} + {{- else if eq .Entry.Kind "header" -}} + {{- header .Entry.Level (include "text" .Entry.Spans) -}} + {{- else if eq .Entry.Kind "list" -}} + {{- template "list" .Entry.List -}} {{- end -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} {{- end -}} - diff --git a/templates/example.gotxt b/templates/example.gotxt index 9fd7c76..ad12cb3 100644 --- a/templates/example.gotxt +++ b/templates/example.gotxt @@ -1,14 +1,19 @@ {{- accordionHeader .Title -}} +{{- spacer -}} {{- template "doc" .Doc -}} +{{- spacer -}} {{- codeBlock "go" .Code -}} +{{- spacer -}} {{- if .HasOutput -}} {{- header 4 "Output" -}} + {{- spacer -}} {{- codeBlock "" .Output -}} + {{- spacer -}} {{- end -}} diff --git a/templates/file.gotxt b/templates/file.gotxt index a7ea263..1da1a71 100644 --- a/templates/file.gotxt +++ b/templates/file.gotxt @@ -1,11 +1,18 @@ -{{.Header -}} +{{if .Header -}} + {{- .Header -}} + {{- spacer -}} +{{- end -}} {{- range .Packages -}} {{- template "package" . -}} + {{- spacer -}} {{- end -}} -{{- .Footer}} +{{- if .Footer -}} + {{- .Footer -}} + {{- spacer -}} +{{- end -}} Generated by {{link "gomarkdoc" "https://github.com/Weborama/gomarkdoc"}} diff --git a/templates/func.gotxt b/templates/func.gotxt index dd504e0..323c517 100644 --- a/templates/func.gotxt +++ b/templates/func.gotxt @@ -1,14 +1,21 @@ {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | rawHeader .Level -}} + {{- rawAnchorHeader .Level (codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver)) .Anchor -}} {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | rawHeader .Level -}} + {{- rawAnchorHeader .Level (codeHref .Location | link (escape .Name) | printf "func %s") .Anchor -}} {{- end -}} +{{- spacer -}} {{- codeBlock "go" .Signature -}} +{{- spacer -}} {{- template "doc" .Doc -}} -{{- range .Examples -}} - {{- template "example" . -}} +{{- if len .Examples -}} + {{- spacer -}} + + {{- range (iter .Examples) -}} + {{- template "example" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} diff --git a/templates/import.gotxt b/templates/import.gotxt index cd476b8..a0494b8 100644 --- a/templates/import.gotxt +++ b/templates/import.gotxt @@ -1,2 +1 @@ -{{- codeBlock "go" .Import -}} - +{{- codeBlock "go" .Import -}} \ No newline at end of file diff --git a/templates/index.gotxt b/templates/index.gotxt index fbc933b..ab2e0e3 100644 --- a/templates/index.gotxt +++ b/templates/index.gotxt @@ -1,45 +1,37 @@ {{- if len .Consts -}} {{- localHref "Constants" | link "Constants" | listEntry 0 -}} + {{- inlineSpacer -}} {{- end -}} {{- if len .Vars -}} {{- localHref "Variables" | link "Variables" | listEntry 0 -}} + {{- inlineSpacer -}} {{- end -}} {{- range .Funcs -}} - {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | localHref | link .Signature | listEntry 0 -}} - {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | localHref | link .Signature | listEntry 0 -}} - {{- end -}} + {{- (link .Signature (rawLocalHref .Anchor)) | listEntry 0 -}} + {{- inlineSpacer -}} {{- end -}} {{- range .Types -}} - {{- codeHref .Location | link (escape .Name) | printf "type %s" | localHref | link .Title | listEntry 0 -}} + {{- (link .Title (rawLocalHref .Anchor)) | listEntry 0 -}} + {{- inlineSpacer -}} {{- range .Funcs -}} - {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | localHref | link .Signature | listEntry 1 -}} - {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | localHref | link .Signature | listEntry 1 -}} - {{- end -}} + {{- (link .Signature (rawLocalHref .Anchor)) | listEntry 1 -}} + {{- inlineSpacer -}} {{- end -}} {{- range .Methods -}} - {{- if .Receiver -}} - {{- codeHref .Location | link (escape .Name) | printf "func \\(%s\\) %s" (escape .Receiver) | localHref | link .Signature | listEntry 1 -}} - {{- else -}} - {{- codeHref .Location | link (escape .Name) | printf "func %s" | localHref | link .Signature | listEntry 1 -}} - {{- end -}} + {{- (link .Signature (rawLocalHref .Anchor)) | listEntry 1 -}} + {{- inlineSpacer -}} {{- end -}} {{- end -}} - -{{- spacer -}} diff --git a/templates/list.gotxt b/templates/list.gotxt new file mode 100644 index 0000000..cd78e9f --- /dev/null +++ b/templates/list.gotxt @@ -0,0 +1,16 @@ +{{- range (iter .Items) -}} + {{- if eq .Entry.Kind "ordered" -}} + {{- .Entry.Number -}}. {{ hangingIndent (include "doc" .Entry) 2 -}} + {{- else -}} + - {{ hangingIndent (include "doc" .Entry) 2 -}} + {{- end -}} + + {{- if (not .Last) -}} + {{- if $.BlankBetween -}} + {{- spacer -}} + {{- else -}} + {{- inlineSpacer -}} + {{- end -}} + {{- end -}} + +{{- end -}} \ No newline at end of file diff --git a/templates/package.gotxt b/templates/package.gotxt index 0bf253c..64c7dd4 100644 --- a/templates/package.gotxt +++ b/templates/package.gotxt @@ -3,43 +3,66 @@ {{- else -}} {{- header .Level .Name -}} {{- end -}} +{{- spacer -}} {{- template "import" . -}} +{{- spacer -}} -{{- template "doc" .Doc -}} +{{- if len .Doc.Blocks -}} + {{- template "doc" .Doc -}} + {{- spacer -}} +{{- end -}} -{{- range .Examples -}} - {{- template "example" . -}} +{{- range (iter .Examples) -}} + {{- template "example" .Entry -}} + {{- spacer -}} {{- end -}} {{- header (add .Level 1) "Index" -}} +{{- spacer -}} {{- template "index" . -}} {{- if len .Consts -}} + {{- spacer -}} {{- header (add .Level 1) "Constants" -}} + {{- spacer -}} - {{- range .Consts -}} - {{- template "value" . -}} + {{- range (iter .Consts) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} {{- end -}} {{- end -}} {{- if len .Vars -}} + {{- spacer -}} {{- header (add .Level 1) "Variables" -}} + {{- spacer -}} - {{- range .Vars -}} - {{- template "value" . -}} + {{- range (iter .Vars) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} {{- end -}} {{- end -}} -{{- range .Funcs -}} - {{- template "func" . -}} +{{- if len .Funcs -}} + {{- spacer -}} + + {{- range (iter .Funcs) -}} + {{- template "func" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Types -}} - {{- template "type" . -}} +{{- if len .Types -}} + {{- spacer -}} + + {{- range (iter .Types) -}} + {{- template "type" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} diff --git a/templates/text.gotxt b/templates/text.gotxt new file mode 100644 index 0000000..1d4b981 --- /dev/null +++ b/templates/text.gotxt @@ -0,0 +1,11 @@ +{{- range . -}} + {{- if eq .Kind "text" -}} + {{- escape .Text -}} + {{- else if eq .Kind "rawText" -}} + {{- .Text -}} + {{- else if eq .Kind "autolink" -}} + {{- .Text -}} + {{- else if eq .Kind "link" -}} + {{- link (escape .Text) .URL -}} + {{- end -}} +{{- end -}} \ No newline at end of file diff --git a/templates/type.gotxt b/templates/type.gotxt index 5f99d7a..3371038 100644 --- a/templates/type.gotxt +++ b/templates/type.gotxt @@ -1,26 +1,53 @@ -{{- codeHref .Location | link (escape .Name) | printf "type %s" | rawHeader .Level -}} +{{- rawAnchorHeader .Level (codeHref .Location | link (escape .Name) | printf "type %s") .Anchor -}} +{{- spacer -}} {{- template "doc" .Doc -}} +{{- spacer -}} {{- codeBlock "go" .Decl -}} -{{- range .Consts -}} - {{- template "value" . -}} +{{- if len .Consts -}} + {{- spacer -}} + + {{- range (iter .Consts) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Vars -}} - {{- template "value" . -}} +{{- if len .Vars -}} + {{- spacer -}} + + {{- range (iter .Vars) -}} + {{- template "value" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Examples -}} - {{- template "example" . -}} +{{- if len .Examples -}} + {{- spacer -}} + + {{- range (iter .Examples) -}} + {{- template "example" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Funcs -}} - {{- template "func" . -}} +{{- if len .Funcs -}} + {{- spacer -}} + + {{- range (iter .Funcs) -}} + {{- template "func" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} -{{- range .Methods -}} - {{- template "func" . -}} +{{- if len .Methods -}} + {{- spacer -}} + + {{- range (iter .Methods) -}} + {{- template "func" .Entry -}} + {{- if (not .Last) -}}{{- spacer -}}{{- end -}} + {{- end -}} {{- end -}} diff --git a/templates/value.gotxt b/templates/value.gotxt index cced729..23354fc 100644 --- a/templates/value.gotxt +++ b/templates/value.gotxt @@ -1,4 +1,6 @@ +{{- anchor .Anchor -}} {{- template "doc" .Doc -}} +{{- spacer -}} {{- codeBlock "go" .Decl -}} diff --git a/testData/docs/.gomarkdoc.yml b/testData/docs/.gomarkdoc.yml new file mode 100644 index 0000000..d45c4fc --- /dev/null +++ b/testData/docs/.gomarkdoc.yml @@ -0,0 +1 @@ +output: "{{.Dir}}/README.md" \ No newline at end of file diff --git a/testData/docs/README.md b/testData/docs/README.md new file mode 100644 index 0000000..5fe3dfb --- /dev/null +++ b/testData/docs/README.md @@ -0,0 +1,170 @@ + + +# docs + +```go +import "github.com/princjef/gomarkdoc/testData/docs" +``` + +Package docs exercises the documentation features of golang 1.19 and above at the package documentation level. + +### This is a heading + +This heading has a paragraph with a reference to the standard library [math/rand]() as well as a function in the file [Func](<#Func>), a type [Type](<#Type>), a type's function [Type.Func](<#Type.Func>), a non\-standard library package [golang.org/x/crypto/bcrypt.Cost](), an external link [Outside Link]() and a \[broken link\]. + +It also has a numbered list: + +1. First +2. Second +3. Third + +Plus one with blank lines: + +1. First + +2. Second + +3. Third + +Non\-numbered lists + +- First another line +- Second +- Third + +Plus blank lines: + +- First + + another paragraph + +- Second + +- Third + +And a golang code block: + +``` +func GolangCode(t int) int { + return t + 1 +} +``` + +And a random code block: + +``` +something + preformatted +in a random + way +``` + +There's also another file with a struct called [AnotherStruct](<#AnotherStruct>) that has additional methods and fields. + +We also have constants like [Constant](<#Constant>) and [Const1](<#Const1>) plus variables like [Var](<#Var>) and and [VarB](<#VarA>). + +## Index + +- [Constants](<#constants>) +- [Variables](<#variables>) +- [func Func\(param int\) int](<#Func>) +- [type AnotherStruct](<#AnotherStruct>) + - [func NewAnotherStruct\(\) \*AnotherStruct](<#NewAnotherStruct>) + - [func \(s \*AnotherStruct\) GetField\(\) string](<#AnotherStruct.GetField>) +- [type Type](<#Type>) + - [func \(t \*Type\) Func\(\)](<#Type.Func>) + + +## Constants + +This is a constant block + +```go +const ( + Const1 = 1 + Const2 = 2 + Const3 = 3 +) +``` + +Constant is a constant. + +```go +const Constant = 3 +``` + +## Variables + +This is a var block + +```go +var ( + VarA = 'a' + VarB = 'b' + VarC = 'c' +) +``` + +Var is a var. + +```go +var Var = 2 +``` + + +## func [Func]() + +```go +func Func(param int) int +``` + +Func is present in this file. + + +## type [AnotherStruct]() + +AnotherStruct has methods like [\\\*AnotherStruct.GetField](<#AnotherStruct.GetField>) and also has an initializer called [NewAnotherStruct](<#NewAnotherStruct>). + +```go +type AnotherStruct struct { + Field string +} +``` + + +### func [NewAnotherStruct]() + +```go +func NewAnotherStruct() *AnotherStruct +``` + +NewAnotherStruct\(\) makes [\\\*AnotherStruct](<#AnotherStruct>). + + +### func \(\*AnotherStruct\) [GetField]() + +```go +func (s *AnotherStruct) GetField() string +``` + +GetField gets \[\*AnotherStruct.Field\]. + + +## type [Type]() + +Type is a type in this file. + +```go +type Type struct{} +``` + + +### func \(\*Type\) [Func]() + +```go +func (t *Type) Func() +``` + +TypeFunc is a func within a type in this file. + +Generated by [gomarkdoc]() diff --git a/testData/docs/anotherFile.go b/testData/docs/anotherFile.go new file mode 100644 index 0000000..b35d644 --- /dev/null +++ b/testData/docs/anotherFile.go @@ -0,0 +1,19 @@ +package docs + +// AnotherStruct has methods like [*AnotherStruct.GetField] and also has an +// initializer called [NewAnotherStruct]. +type AnotherStruct struct { + Field string +} + +// NewAnotherStruct() makes [*AnotherStruct]. +func NewAnotherStruct() *AnotherStruct { + return &AnotherStruct{ + Field: "test", + } +} + +// GetField gets [*AnotherStruct.Field]. +func (s *AnotherStruct) GetField() string { + return s.Field +} diff --git a/testData/docs/docs.go b/testData/docs/docs.go new file mode 100644 index 0000000..12f9fdf --- /dev/null +++ b/testData/docs/docs.go @@ -0,0 +1,92 @@ +// Package docs exercises the documentation features of golang 1.19 and above at +// the package documentation level. +// +// # This is a heading +// +// This heading has a paragraph with a reference to the standard library +// [math/rand] as well as a function in the file [Func], a type [Type], a type's +// function [Type.Func], a non-standard library package +// [golang.org/x/crypto/bcrypt.Cost], an external link [Outside Link] and +// a [broken link]. +// +// It also has a numbered list: +// 1. First +// 2. Second +// 3. Third +// +// Plus one with blank lines: +// +// 1. First +// +// 2. Second +// +// 3. Third +// +// Non-numbered lists +// - First +// another line +// - Second +// - Third +// +// Plus blank lines: +// +// - First +// +// another paragraph +// +// - Second +// +// - Third +// +// And a golang code block: +// +// func GolangCode(t int) int { +// return t + 1 +// } +// +// And a random code block: +// +// something +// preformatted +// in a random +// way +// +// There's also another file with a struct called [AnotherStruct] that has +// additional methods and fields. +// +// We also have constants like [Constant] and [Const1] plus variables like +// [Var] and and [VarB]. +// +// [Outside Link]: https://golang.org/doc/articles/json_and_go.html +package docs + +// Func is present in this file. +func Func(param int) int { + return param +} + +// Type is a type in this file. +type Type struct{} + +// TypeFunc is a func within a type in this file. +func (t *Type) Func() {} + +// Constant is a constant. +const Constant = 3 + +// Var is a var. +var Var = 2 + +// This is a constant block +const ( + Const1 = 1 + Const2 = 2 + Const3 = 3 +) + +// This is a var block +var ( + VarA = 'a' + VarB = 'b' + VarC = 'c' +) diff --git a/testData/embed/README.md b/testData/embed/README.md index bec4490..2dcd392 100644 --- a/testData/embed/README.md +++ b/testData/embed/README.md @@ -7,17 +7,18 @@ This is content before the embed # embed ```go -import "github.com/Weborama/gomarkdoc/testData/embed" +import "github.com/princjef/gomarkdoc/testData/embed" ``` Package embed tests out embedding of documentation in an existing readme. ## Index -- [func EmbeddedFunc(param int) int](<#func-embeddedfunc>) +- [func EmbeddedFunc\(param int\) int](<#EmbeddedFunc>) -## func [EmbeddedFunc]() + +## func [EmbeddedFunc]() ```go func EmbeddedFunc(param int) int @@ -25,9 +26,7 @@ func EmbeddedFunc(param int) int EmbeddedFunc is present in embedded content. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() @@ -41,17 +40,18 @@ This is content after the embed # embed ```go -import "github.com/Weborama/gomarkdoc/testData/embed" +import "github.com/princjef/gomarkdoc/testData/embed" ``` Package embed tests out embedding of documentation in an existing readme. ## Index -- [func EmbeddedFunc(param int) int](<#func-embeddedfunc>) +- [func EmbeddedFunc\(param int\) int](<#EmbeddedFunc>) -## func [EmbeddedFunc]() + +## func [EmbeddedFunc]() ```go func EmbeddedFunc(param int) int @@ -59,9 +59,7 @@ func EmbeddedFunc(param int) int EmbeddedFunc is present in embedded content. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() @@ -75,17 +73,18 @@ This is content after the second embed # embed ```go -import "github.com/Weborama/gomarkdoc/testData/embed" +import "github.com/princjef/gomarkdoc/testData/embed" ``` Package embed tests out embedding of documentation in an existing readme. ## Index -- [func EmbeddedFunc(param int) int](<#func-embeddedfunc>) +- [func EmbeddedFunc\(param int\) int](<#EmbeddedFunc>) -## func [EmbeddedFunc]() + +## func [EmbeddedFunc]() ```go func EmbeddedFunc(param int) int @@ -93,9 +92,7 @@ func EmbeddedFunc(param int) int EmbeddedFunc is present in embedded content. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() diff --git a/testData/generics/README.md b/testData/generics/README.md new file mode 100644 index 0000000..27e4aa2 --- /dev/null +++ b/testData/generics/README.md @@ -0,0 +1,55 @@ + + +# generics + +```go +import "github.com/princjef/gomarkdoc/testData/generics" +``` + +## Index + +- [func Func\[S int | float64\]\(s S\) S](<#Func>) +- [type Generic](<#Generic>) + - [func NewGeneric\[T any\]\(param T\) Generic\[T\]](<#NewGeneric>) + - [func \(g Generic\[T\]\) Method\(\)](<#Generic[T].Method>) + + + +## func [Func]() + +```go +func Func[S int | float64](s S) S +``` + +Func is a generic function. + + +## type [Generic]() + +Generic is a generic struct. + +```go +type Generic[T any] struct { + Field T +} +``` + + +### func [NewGeneric]() + +```go +func NewGeneric[T any](param T) Generic[T] +``` + +NewGeneric produces a new [Generic](<#Generic>) struct. + + +### func \(Generic\[T\]\) [Method]() + +```go +func (g Generic[T]) Method() +``` + +Method is a method of a generic type. + +Generated by [gomarkdoc]() diff --git a/testData/generics/generics.go b/testData/generics/generics.go new file mode 100644 index 0000000..1dc7cf7 --- /dev/null +++ b/testData/generics/generics.go @@ -0,0 +1,19 @@ +package generics + +// Generic is a generic struct. +type Generic[T any] struct { + Field T +} + +// NewGeneric produces a new [Generic] struct. +func NewGeneric[T any](param T) Generic[T] { + return Generic[T]{Field: param} +} + +// Method is a method of a generic type. +func (g Generic[T]) Method() {} + +// Func is a generic function. +func Func[S int | float64](s S) S { + return s +} diff --git a/testData/lang/function/README.md b/testData/lang/function/README.md new file mode 100644 index 0000000..9e34416 --- /dev/null +++ b/testData/lang/function/README.md @@ -0,0 +1,241 @@ + + +# function + +```go +import "github.com/princjef/gomarkdoc/testData/lang/function" +``` + +## Index + +- [Constants](<#constants>) +- [Variables](<#variables>) +- [func Standalone\(p1 int, p2 string\) \(int, error\)](<#Standalone>) +- [type Generic](<#Generic>) + - [func \(r Generic\[T\]\) WithGenericReceiver\(\)](<#Generic[T].WithGenericReceiver>) +- [type Receiver](<#Receiver>) + - [func New\(\) Receiver](<#New>) + - [func \(r \*Receiver\) WithPtrReceiver\(\)](<#Receiver.WithPtrReceiver>) + - [func \(r Receiver\) WithReceiver\(\)](<#Receiver.WithReceiver>) + + +## Constants + +Set of constants for this package. + +```go +const ( + ConstA = "string" + ConstB = true +) +``` + +## Variables + +Variable is a package\-level variable. + +```go +var Variable = 5 +``` + + +## func [Standalone]() + +```go +func Standalone(p1 int, p2 string) (int, error) +``` + +Standalone provides a function that is not part of a type. + +Additional description can be provided in subsequent paragraphs, including code blocks and headers + +### Header A + +This section contains a code block. + +``` +Code Block +More of Code Block +``` + +
Example +

+ + + +```go +package main + +import ( + "fmt" + + "github.com/princjef/gomarkdoc/testData/lang/function" +) + +func main() { + // Comment + res, _ := function.Standalone(2, "abc") + fmt.Println(res) +} +``` + +#### Output + +``` +2 +``` + +

+
+ +
Example (Zero) +

+ + + +```go +package main + +import ( + "fmt" + + "github.com/princjef/gomarkdoc/testData/lang/function" +) + +func main() { + res, _ := function.Standalone(0, "def") + fmt.Println(res) +} +``` + +#### Output + +``` +0 +``` + +

+
+ + +## type [Generic]() + +Generic is a struct with a generic type. + +```go +type Generic[T any] struct{} +``` + + +### func \(Generic\[T\]\) [WithGenericReceiver]() + +```go +func (r Generic[T]) WithGenericReceiver() +``` + +WithGenericReceiver has a receiver with a generic type. + +
Example +

+ + + +```go +package main + +import ( + "github.com/princjef/gomarkdoc/testData/lang/function" +) + +func main() { + r := function.Generic[int]{} + r.WithGenericReceiver() +} +``` + +

+
+ + +## type [Receiver]() + +Receiver is a type used to demonstrate functions with receivers. + +```go +type Receiver struct{} +``` + +
Example +

+ + + +```go +package main + +import ( + "fmt" + + "github.com/princjef/gomarkdoc/testData/lang/function" +) + +func main() { + // Add some comments + r := &function.Receiver{} + // And some more + fmt.Println(r) +} +``` + +

+
+ +
Example (Sub Test) +

+ + + +```go +package main + +import ( + "github.com/princjef/gomarkdoc/testData/lang/function" +) + +func main() { + var r function.Receiver + r.WithReceiver() +} +``` + +

+
+ + +### func [New]() + +```go +func New() Receiver +``` + +New is an initializer for Receiver. + + +### func \(\*Receiver\) [WithPtrReceiver]() + +```go +func (r *Receiver) WithPtrReceiver() +``` + +WithPtrReceiver has a pointer receiver. + + +### func \(Receiver\) [WithReceiver]() + +```go +func (r Receiver) WithReceiver() +``` + +WithReceiver has a receiver. + +Generated by [gomarkdoc]() diff --git a/testData/lang/function/func_test.go b/testData/lang/function/func_test.go index 648cf49..62ec2e6 100644 --- a/testData/lang/function/func_test.go +++ b/testData/lang/function/func_test.go @@ -7,6 +7,7 @@ import ( ) func ExampleStandalone() { + // Comment res, _ := function.Standalone(2, "abc") fmt.Println(res) // Output: 2 @@ -19,7 +20,9 @@ func ExampleStandalone_zero() { } func ExampleReceiver() { + // Add some comments r := &function.Receiver{} + // And some more fmt.Println(r) } diff --git a/testData/nested/README.md b/testData/nested/README.md index 31cc8ea..e4941e9 100755 --- a/testData/nested/README.md +++ b/testData/nested/README.md @@ -3,15 +3,16 @@ # nested ```go -import "github.com/Weborama/gomarkdoc/testData/nested" +import "github.com/princjef/gomarkdoc/testData/nested" ``` ## Index -- [func Parent() int](<#func-parent>) +- [func Parent\(\) int](<#Parent>) -## func [Parent]() + +## func [Parent]() ```go func Parent() int @@ -19,6 +20,4 @@ func Parent() int Parent is in the parent package. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() diff --git a/testData/nested/inner/README.md b/testData/nested/inner/README.md index 79d6b0f..1cc5ed6 100755 --- a/testData/nested/inner/README.md +++ b/testData/nested/inner/README.md @@ -3,15 +3,16 @@ # inner ```go -import "github.com/Weborama/gomarkdoc/testData/nested/inner" +import "github.com/princjef/gomarkdoc/testData/nested/inner" ``` ## Index -- [func Child() int](<#func-child>) +- [func Child\(\) int](<#Child>) -## func [Child]() + +## func [Child]() ```go func Child() int @@ -19,6 +20,4 @@ func Child() int Child is in the child package. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() diff --git a/testData/simple/README.md b/testData/simple/README.md index d61315f..2fc6aa9 100755 --- a/testData/simple/README.md +++ b/testData/simple/README.md @@ -3,19 +3,20 @@ # simple ```go -import "github.com/Weborama/gomarkdoc/testData/simple" +import "github.com/princjef/gomarkdoc/testData/simple" ``` Package simple contains, some simple code to exercise basic scenarios for documentation purposes. ## Index -- [type Num](<#type-num>) - - [func AddNums(num1, num2 Num) Num](<#func-addnums>) - - [func (n Num) Add(num Num) Num](<#func-num-add>) +- [type Num](<#Num>) + - [func AddNums\(num1, num2 Num\) Num](<#AddNums>) + - [func \(n Num\) Add\(num Num\) Num](<#Num.Add>) -## type [Num]() + +## type [Num]() Num is a number. @@ -25,7 +26,8 @@ It is just a test type so that we can make sure this works. type Num int ``` -### func [AddNums]() + +### func [AddNums]() ```go func AddNums(num1, num2 Num) Num @@ -33,7 +35,8 @@ func AddNums(num1, num2 Num) Num AddNums adds two Nums together. -### func \(Num\) [Add]() + +### func \(Num\) [Add]() ```go func (n Num) Add(num Num) Num @@ -41,6 +44,4 @@ func (n Num) Add(num Num) Num Add adds the other num to this one. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() diff --git a/testData/tags/README.md b/testData/tags/README.md index 7aac48e..eb74b01 100755 --- a/testData/tags/README.md +++ b/testData/tags/README.md @@ -3,18 +3,19 @@ # tags ```go -import "github.com/Weborama/gomarkdoc/testData/tags" +import "github.com/princjef/gomarkdoc/testData/tags" ``` Package tags contains code to demonstrate usage of build tags. ## Index -- [func Tagged() int](<#func-tagged>) -- [func Untagged() int](<#func-untagged>) +- [func Tagged\(\) int](<#Tagged>) +- [func Untagged\(\) int](<#Untagged>) -## func [Tagged]() + +## func [Tagged]() ```go func Tagged() int @@ -22,7 +23,8 @@ func Tagged() int Tagged is only visible with tags. -## func [Untagged]() + +## func [Untagged]() ```go func Untagged() int @@ -30,6 +32,4 @@ func Untagged() int Untagged is visible without tags. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() diff --git a/testData/unexported/README.md b/testData/unexported/README.md index 1a5067c..8c1c65b 100755 --- a/testData/unexported/README.md +++ b/testData/unexported/README.md @@ -3,20 +3,21 @@ # unexported ```go -import "github.com/Weborama/gomarkdoc/testData/unexported" +import "github.com/princjef/gomarkdoc/testData/unexported" ``` Package unexported contains some simple code to exercise basic scenarios for documentation purposes. ## Index -- [type Num](<#type-num>) - - [func AddNums(num1, num2 Num) Num](<#func-addnums>) - - [func addInternal(num1, num2 Num) Num](<#func-addinternal>) - - [func (n Num) Add(num Num) Num](<#func-num-add>) +- [type Num](<#Num>) + - [func AddNums\(num1, num2 Num\) Num](<#AddNums>) + - [func addInternal\(num1, num2 Num\) Num](<#addInternal>) + - [func \(n Num\) Add\(num Num\) Num](<#Num.Add>) -## type [Num]() + +## type [Num]() Num is a number. @@ -26,7 +27,8 @@ It is just a test type so that we can make sure this works. type Num int ``` -### func [AddNums]() + +### func [AddNums]() ```go func AddNums(num1, num2 Num) Num @@ -34,7 +36,8 @@ func AddNums(num1, num2 Num) Num AddNums adds two Nums together. -### func [addInternal]() + +### func [addInternal]() ```go func addInternal(num1, num2 Num) Num @@ -42,7 +45,8 @@ func addInternal(num1, num2 Num) Num addInternal is a private version of AddNums. -### func \(Num\) [Add]() + +### func \(Num\) [Add]() ```go func (n Num) Add(num Num) Num @@ -50,6 +54,4 @@ func (n Num) Add(num Num) Num Add adds the other num to this one. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]() diff --git a/testData/untagged/README.md b/testData/untagged/README.md index b9eb721..2aa063c 100755 --- a/testData/untagged/README.md +++ b/testData/untagged/README.md @@ -3,17 +3,18 @@ # untagged ```go -import "github.com/Weborama/gomarkdoc/testData/untagged" +import "github.com/princjef/gomarkdoc/testData/untagged" ``` Package untagged contains code to demonstrate usage of build tags. ## Index -- [func Untagged() int](<#func-untagged>) +- [func Untagged\(\) int](<#Untagged>) -## func [Untagged]() + +## func [Untagged]() ```go func Untagged() int @@ -21,6 +22,4 @@ func Untagged() int Untagged is visible without tags. - - -Generated by [gomarkdoc]() +Generated by [gomarkdoc]()