diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..a51872b --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,1073 @@ +# This file contains all available configuration options +# with their default values. +# options for analysis running +run: + # The default concurrency value is the number of available CPU. + concurrency: 4 + # Timeout for analysis, e.g. 30s, 5m. + # Default: 1m + timeout: 5m + # Exit code when at least one issue was found. + # Default: 1 + issues-exit-code: 2 + # Include test files or not. + # Default: true + tests: true + # list of build tags, all linters use it. Default is empty list. + build-tags: + - integration + # Which dirs to skip: issues from them won't be reported. + skip-dirs: + - internal/client/graphql + - internal/handler/graphql + - internal/handler/graphql/generated + - internal/compatibility + # Enables skipping of directories: + # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + # Default: true + skip-dirs-use-default: true + # Which files to skip: they will be analyzed, but issues from them won't be reported. + skip-files: + - internal/handler/graphql/schema.resolvers.go + # - ".*\\.my\\.go$" + # - lib/bad.go + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + # modules-download-mode: readonly|release|vendor + modules-download-mode: readonly + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + allow-parallel-runners: false + # Define the Go version limit. + # Mainly related to generics support since go1.18. + # Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.18 + go: '1.20' + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" + format: colored-line-number + # Print lines of code with issue. + # Default: true + print-issued-lines: true + # Print linter name in the end of issue text. + # Default: true + print-linter-name: true + # Make issues output unique by line. + # Default: true + uniq-by-line: true + # Add a prefix to the output file references. + # Default is no prefix. + path-prefix: "" + # Sort results by: filepath, line and column. + sort-results: true + +# all available settings of specific linters +linters-settings: + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 10 + # The maximal average package complexity. + # If it's higher than 0.0 (float) the check is enabled + # Default: 0.0 + package-average: 5.0 + # Should ignore tests. + # Default: false + skip-tests: true + decorder: + # Required order of `type`, `const`, `var` and `func` declarations inside a file. + # Default: types before constants before variables before functions. + dec-order: + - const + - var + - type + - func + # If true, order of declarations is not checked at all. + # Default: true (disabled) + disable-dec-order-check: false + # If true, `init` func can be anywhere in file (does not have to be declared before all other functions). + # Default: true (disabled) + disable-init-func-first-check: false + # If true, multiple global `type`, `const` and `var` declarations are allowed. + # Default: true (disabled) + disable-dec-num-check: true + depguard: + # https://golangci-lint.run/usage/linters/#depguard + rules: + main: + deny: + - pkg: "github.com/sirupsen/logrus" + desc: Should be replaced by zerolog + - pkg: "github.com/pkg/errors" + desc: Should be replaced by standard lib errors package + dogsled: # https://golangci-lint.run/usage/linters/#dogsled + # Checks assignments with too many blank identifiers. + # Default: 2 + max-blank-identifiers: 2 + dupl: + # Tokens count to trigger issue. + # Default: 150 + threshold: 150 + errcheck: + # report about not checking of errors in type assertions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: true + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: true + # [deprecated] comma-separated list of pairs of the form pkg:regex + # the regex is used to ignore names within pkg. (default "fmt:.*"). + # see https://github.com/kisielk/errcheck#the-deprecated-method for details + # ignore: fmt:.*,io/ioutil:^Read.* + # path to a file containing a list of functions to exclude from checking + # see https://github.com/kisielk/errcheck#excluding-functions for details + errorlint: + # Check whether fmt.Errorf uses the %w verb for formatting errors. + # See the https://github.com/polyfloyd/go-errorlint for caveats. + # Default: true + errorf: true + # Permit more than 1 %w verb, valid per Go 1.20 (Requires errorf:true) + # Default: true + errorf-multi: true + # Check for plain type assertions and type switches. + # Default: true + asserts: true + # Check for plain error comparisons. + # Default: true + comparison: true + exhaustive: + # Program elements to check for exhaustiveness. + # Default: [ switch ] + check: + - switch + - map + # Check switch statements in generated files also. + # Default: false + check-generated: false + # Presence of "default" case in switch statements satisfies exhaustiveness, + # even if all enum members are not listed. + # Default: false + default-signifies-exhaustive: true + # Enum members matching the supplied regex do not have to be listed in + # switch statements to satisfy exhaustiveness. + # Default: "" + ignore-enum-members: "Example.+" + # Enum types matching the supplied regex do not have to be listed in + # switch statements to satisfy exhaustiveness. + # Default: "" + ignore-enum-types: "Example.+" + # Consider enums only in package scopes, not in inner scopes. + # Default: false + package-scope-only: true + # Only run exhaustive check on switches with "//exhaustive:enforce" comment. + # Default: false + explicit-exhaustive-switch: true + # Only run exhaustive check on map literals with "//exhaustive:enforce" comment. + # Default: false + explicit-exhaustive-map: true + forbidigo: + # Forbid the following identifiers (list of regexp). + # Default: ["^(fmt\\.Print(|f|ln)|print|println)$"] + forbid: + # Builtin function: + - ^print.*$ + # Optional message that gets included in error reports. + - p: ^fmt\.Print.*$ + msg: Do not commit print statements. + # Alternatively, put messages at the end of the regex, surrounded by `(# )?` + # Escape any special characters. Those messages get included in error reports. + - 'fmt\.Print.*(# Do not commit print statements\.)?' + # Forbid spew Dump, whether it is called as function or method. + # Depends on analyze-types below. + - ^spew\.(ConfigState\.)?Dump$ + # The package name might be ambiguous. + # The full import path can be used as additional criteria. + # Depends on analyze-types below. + - p: ^v1.Dump$ + pkg: ^example.com/pkg/api/v1$ + # Exclude godoc examples from forbidigo checks. + # Default: true + exclude-godoc-examples: false + # Instead of matching the literal source code, + # use type information to replace expressions with strings that contain the package name + # and (for methods and fields) the type name. + # This makes it possible to handle import renaming and forbid struct fields and methods. + # Default: false + analyze-types: true + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 + lines: 150 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 + statements: 40 + gci: + # Section configuration to compare against. + # Section names are case-insensitive and may contain parameters in (). + # The default order of sections is `standard > default > custom > blank > dot`, + # If `custom-order` is `true`, it follows the order of `sections` option. + # Default: ["standard", "default"] + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix(github.com/kevinmichaelchen/graphql-schema-picker) # Custom section: groups all imports with the specified Prefix. + - blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled. + - dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled. + # Skip generated files. + # Default: true + skip-generated: false + # Enable custom order of sections. + # If `true`, make the section order the same as the order of `sections`. + # Default: false + custom-order: true + goconst: + # Minimal length of string constant. + # Default: 3 + min-len: 3 + # Minimum occurrences of constant string count to trigger issue. + # Default: 3 + min-occurrences: 3 + # Ignore test files. + # Default: false + ignore-tests: true + gocritic: + disabled-checks: + - hugeParam + - rangeValCopy + - timeCmpSimplify + # https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - diagnostic + - style + - performance + - opinionated + settings: + captLocal: # must be valid enabled check name + paramsOnly: true + godot: + # check all top-level comments, not only declarations + check-all: false + gofmt: + # Simplify code: gofmt with `-s` option. + # Default: true + simplify: false + # Apply the rewrite rules to the source before reformatting. + # https://pkg.go.dev/cmd/gofmt + # Default: [] + rewrite-rules: + - pattern: 'interface{}' + replacement: 'any' + - pattern: 'a[b:len(a)]' + replacement: 'a[b:]' + gofumpt: + # Choose whether to use the extra rules. + # Default: false + extra-rules: false + goheader: + values: + const: + # define here const type values in format k:v, for example: + # YEAR: 2020 + # COMPANY: MY COMPANY + regexp: + # define here regexp type values, for example + # AUTHOR: .*@mycompany\.com + template: "" + # put here copyright header template for source code files, for example: + # {{ AUTHOR }} {{ COMPANY }} {{ YEAR }} + # SPDX-License-Identifier: Apache-2.0 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at: + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + template-path: "" + # also as alternative of directive 'template' you may put the path to file with the template source + gomnd: + # List of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + # Default: ["argument", "case", "condition", "operation", "return", "assign"] + checks: + - argument + - case + - condition + - operation + - return + - assign + # List of numbers to exclude from analysis. + # The numbers should be written as string. + # Values always ignored: "1", "1.0", "0" and "0.0" + # Default: [] + ignored-numbers: [] + # List of file patterns to exclude from analysis. + # Values always ignored: `.+_test.go` + # Default: [] + ignored-files: + - 'magic1_.+\.go$' + # List of function patterns to exclude from analysis. + # Following functions are always ignored: `time.Date`, + # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, + # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. + # Default: [] + ignored-functions: + - '^math\.' + - '^http\.StatusText$' + gomodguard: + allowed: + modules: [] # List of allowed modules + # - gopkg.in/yaml.v2 + domains: # List of allowed module domains + - github.com + - go.uber.org/fx + blocked: + modules: [] # List of blocked modules + # - github.com/uudashr/go-module: # Blocked module + # recommendations: # Recommended modules that should be used instead (Optional) + # - golang.org/x/mod + # reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) + versions: [] # List of blocked module version constraints + # - github.com/mitchellh/go-homedir: # Blocked module with version constraint + # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons + # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional) + # settings per analyzer + settings: + printf: # analyzer name, run `go tool vet help` to see all analyzers + funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + # enable or disable analyzers by name + enable: + - atomicalign + enable-all: false + disable: + - shadow + disable-all: false + gocognit: + # Minimal code complexity to report. + # Default: 30 (but we recommend 10-20) + min-complexity: 10 + goimports: + # A comma-separated list of prefixes, which, if set, checks import paths + # with the given prefixes are grouped after 3rd-party packages. + # Default: "" + local-prefixes: github.com/kevinmichaelchen/graphql-schema-picker + govet: + # Report about shadowed variables. + # Default: false + check-shadowing: true + # Settings per analyzer. + settings: + # Analyzer name, run `go tool vet help` to see all analyzers. + printf: + # Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`). + # Default: [] + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + strict: true + unusedresult: + # Comma-separated list of functions whose results must be used + # (in addition to defaults context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue, + # errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse) + # Default [] + funcs: + - pkg.MyFunc + # Comma-separated list of names of methods of type func() string whose results must be used + # (in addition to default Error,String) + # Default [] + stringmethods: + - MyMethod + # Enable all analyzers. + # Default: false + enable-all: true + disable: + - fieldalignment + interfacebloat: + # The maximum number of methods allowed for an interface. + # Default: 10 + max: 1 + lll: + # max line length, lines longer will be reported. Default is 120. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option + line-length: 80 + # tab width in spaces. Default to 1. + tab-width: 1 + maintidx: + # Show functions with maintainability index lower than N. + # A high index indicates better maintainability (it's kind of the opposite of complexity). + # Default: 20 + under: 20 + misspell: + # Correct spellings using locale preferences for US or UK. + # Default is to use a neutral variety of English. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + locale: US + ignore-words: + - someword + nakedret: + # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 + max-func-lines: 30 + nestif: + # minimal complexity of if statements to report, 5 by default + min-complexity: 3 + nolintlint: + # Enable to ensure that nolint directives are all used. Default is true. + allow-unused: true + # Disable to ensure that nolint directives don't have a leading space. Default is true. + allow-leading-space: false + # Exclude following linters from requiring an explanation. Default is []. + allow-no-explanation: [] + # Enable to require an explanation of nonzero length after each nolint directive. Default is false. + require-explanation: true + # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. + require-specific: true + reassign: + # Patterns for global variable names that are checked for reassignment. + # See https://github.com/curioswitch/go-reassign#usage + # Default: ["EOF", "Err.*"] + patterns: + - ".*" + revive: + # Maximum number of open files at the same time. + # See https://github.com/mgechev/revive#command-line-flags + # Defaults to unlimited. + max-open-files: 2048 + # When set to false, ignores files with "GENERATED" header, similar to golint. + # See https://github.com/mgechev/revive#available-rules for details. + # Default: false + ignore-generated-header: true + # Sets the default severity. + # See https://github.com/mgechev/revive#configuration + # Default: warning + severity: error + # Enable all available rules. + # Default: false + enable-all-rules: true + # Sets the default failure confidence. + # This means that linting errors with less than 0.8 confidence will be ignored. + # Default: 0.8 + confidence: 0.1 + rules: + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#add-constant + - name: add-constant + severity: warning + disabled: true + arguments: + - maxLitCount: "3" + allowStrs: '""' + allowInts: "0,1,2" + allowFloats: "0.0,0.,1.0,1.,2.0,2." + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#argument-limit + - name: argument-limit + severity: warning + disabled: false + arguments: [ 6 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#atomic + - name: atomic + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#banned-characters + - name: banned-characters + severity: warning + disabled: false + arguments: [ "Ω", "Σ", "σ", "7" ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bare-return + - name: bare-return + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#blank-imports + - name: blank-imports + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr + - name: bool-literal-in-expr + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#call-to-gc + - name: call-to-gc + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cognitive-complexity + - name: cognitive-complexity + severity: warning + disabled: true + arguments: [ 10 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#comment-spacings + - name: comment-spacings + severity: warning + disabled: false + arguments: + - mypragma + - otherpragma + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#confusing-naming + - name: confusing-naming + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#confusing-results + - name: confusing-results + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#constant-logical-expr + - name: constant-logical-expr + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument + - name: context-as-argument + severity: warning + disabled: false + arguments: + - allowTypesBefore: "*testing.T,*github.com/user/repo/testing.Harness" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-keys-type + - name: context-keys-type + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cyclomatic + - name: cyclomatic + severity: warning + disabled: true + arguments: [ 10 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#datarace + - name: datarace + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#deep-exit + - name: deep-exit + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#defer + - name: defer + severity: warning + disabled: false + arguments: + - [ "call-chain", "loop" ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#dot-imports + - name: dot-imports + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#duplicated-imports + - name: duplicated-imports + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return + - name: early-return + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block + - name: empty-block + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines + - name: empty-lines + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-naming + - name: error-naming + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-return + - name: error-return + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-strings + - name: error-strings + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#errorf + - name: errorf + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported + - name: exported + severity: warning + disabled: false + arguments: + - "checkPrivateReceivers" + - "sayRepetitiveInsteadOfStutters" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#file-header + - name: file-header + severity: warning + disabled: true + arguments: + - This is the text that must appear at the top of source files. + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#flag-parameter + - name: flag-parameter + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-result-limit + - name: function-result-limit + severity: warning + disabled: false + arguments: [ 2 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-length + - name: function-length + severity: warning + disabled: true + arguments: [ 40, 150 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#get-return + - name: get-return + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#identical-branches + - name: identical-branches + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#if-return + - name: if-return + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#increment-decrement + - name: increment-decrement + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#indent-error-flow + - name: indent-error-flow + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#imports-blacklist + - name: imports-blacklist + severity: warning + disabled: false + arguments: + - "crypto/md5" + - "crypto/sha1" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing + - name: import-shadowing + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#line-length-limit + - name: line-length-limit + severity: warning + disabled: true + arguments: [ 80 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#max-public-structs + - name: max-public-structs + severity: warning + disabled: false + arguments: [ 3 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-parameter + - name: modifies-parameter + severity: warning + disabled: true + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-value-receiver + - name: modifies-value-receiver + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#nested-structs + - name: nested-structs + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#optimize-operands-order + - name: optimize-operands-order + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments + - name: package-comments + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range + - name: range + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-in-closure + - name: range-val-in-closure + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-address + - name: range-val-address + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#receiver-naming + - name: receiver-naming + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redefines-builtin-id + - name: redefines-builtin-id + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-of-int + - name: string-of-int + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-format + - name: string-format + severity: warning + disabled: false + arguments: + - - 'core.WriteError[1].Message' + - '/^([^A-Z]|$)/' + - must not start with a capital letter + - - 'fmt.Errorf[0]' + - '/(^|[^\.!?])$/' + - must not end in punctuation + - - panic + - '/^[^\n]*$/' + - must not contain line breaks + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag + - name: struct-tag + arguments: + - "json,inline" + - "bson,outline,gnu" + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#superfluous-else + - name: superfluous-else + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-equal + - name: time-equal + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-naming + - name: time-naming + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-naming + - name: var-naming + severity: warning + disabled: false + arguments: + - [ "ID" ] # AllowList + - [ "VM" ] # DenyList + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-declaration + - name: var-declaration + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unconditional-recursion + - name: unconditional-recursion + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-naming + - name: unexported-naming + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return + - name: unexported-return + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error + - name: unhandled-error + severity: warning + disabled: false + arguments: + - "fmt.Printf" + - "myFunction" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unnecessary-stmt + - name: unnecessary-stmt + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unreachable-code + - name: unreachable-code + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter + - name: unused-parameter + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver + - name: unused-receiver + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break + - name: useless-break + severity: warning + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value + - name: waitgroup-by-value + severity: warning + disabled: false + rowserrcheck: + packages: + - github.com/jmoiron/sqlx + staticcheck: + go: "1.20" + # SAxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ "all" ] + stylecheck: + # STxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ "all" ] + # https://staticcheck.io/docs/configuration/options/#dot_import_whitelist + # Default: ["github.com/mmcloughlin/avo/build", "github.com/mmcloughlin/avo/operand", "github.com/mmcloughlin/avo/reg"] + dot-import-whitelist: + - fmt + # https://staticcheck.io/docs/configuration/options/#initialisms + # Default: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"] + initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS" ] + # https://staticcheck.io/docs/configuration/options/#http_status_code_whitelist + # Default: ["200", "400", "404", "500"] + http-status-code-whitelist: [ "200", "400", "404", "500" ] + tagalign: + # Align and sort can be used together or separately. + # + # Whether enable align. If true, the struct tags will be aligned. + # eg: + # type FooBar struct { + # Bar string `json:"bar" validate:"required"` + # FooFoo int8 `json:"foo_foo" validate:"required"` + # } + # will be formatted to: + # type FooBar struct { + # Bar string `json:"bar" validate:"required"` + # FooFoo int8 `json:"foo_foo" validate:"required"` + # } + # Default: true. + align: true + # Whether enable tags sort. + # If true, the tags will be sorted by name in ascending order. + # eg: `xml:"bar" json:"bar" validate:"required"` -> `json:"bar" validate:"required" xml:"bar"` + # Default: true + sort: true + # Specify the order of tags, the other tags will be sorted by name. + # This option will be ignored if `sort` is false. + # Default: [] + order: + - json + - yaml + - yml + - toml + - mapstructure + - binding + - validate + testpackage: + # regexp pattern to skip files + skip-regexp: (export|internal)_test\.go + unparam: + # Inspect exported functions. + # + # Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + # + # Default: false + check-exported: true + unused: + # treat code as a program (not a library) and report unused exported identifiers; default is false. + # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find funcs usages. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + varnamelen: + ignore-names: + - tc + whitespace: + # Enforces newlines (or comments) after every multi-line if statement. + # Default: false + multi-if: true + # Enforces newlines (or comments) after every multi-line function signature. + # Default: false + multi-func: false + wrapcheck: + # An array of strings that specify substrings of signatures to ignore. + # If this set, it will override the default set of ignored signatures. + # See https://github.com/tomarrell/wrapcheck#configuration for more information. + # Default: [".Errorf(", "errors.New(", "errors.Unwrap(", ".Wrap(", ".Wrapf(", ".WithMessage(", ".WithMessagef(", ".WithStack("] + ignoreSigs: + - .Errorf( + - errors.New( + - errors.Unwrap( + - .Wrap( + - .Wrapf( + - .WithMessage( + - .WithMessagef( + - .WithStack( + # An array of strings that specify regular expressions of signatures to ignore. + # Default: [] + ignoreSigRegexps: + - \.New.*Error\( + # An array of strings that specify globs of packages to ignore. + # Default: [] + ignorePackageGlobs: + - encoding/* + # An array of strings that specify regular expressions of interfaces to ignore. + # Default: [] + ignoreInterfaceRegexps: + - ^(?i)c(?-i)ach(ing|e) + wsl: + # See https://github.com/bombsimon/wsl/blob/master/doc/configuration.md for documentation of available settings. + # These are the defaults for `golangci-lint`. + + # Do strict checking when assigning from append (x = append(x, y)). If + # this is set to true - the append call must append either a variable + # assigned, called or used on the line above. + strict-append: true + # Allows assignments to be cuddled with variables used in calls on + # line above and calls to be cuddled with assignments of variables + # used in call on line above. + allow-assign-and-call: true + # Allows assignments to be cuddled with anything. + allow-assign-and-anything: false + # Allows cuddling to assignments even if they span over multiple lines. + allow-multiline-assign: true + # If the number of lines in a case block is equal to or lager than this + # number, the case *must* end white a newline. + force-case-trailing-whitespace: 0 + # Allow blocks to end with comments. + allow-trailing-comment: false + # Allow multiple comments in the beginning of a block separated with newline. + allow-separated-leading-comment: false + # Allow multiple var/declaration statements to be cuddled. + allow-cuddle-declarations: false + # A list of call idents that everything can be cuddled with. + # Defaults to calls looking like locks. + allow-cuddle-with-calls: [ "Lock", "RLock" ] + # AllowCuddleWithRHS is a list of right hand side variables that is allowed + # to be cuddled with anything. Defaults to assignments or calls looking + # like unlocks. + allow-cuddle-with-rhs: [ "Unlock", "RUnlock" ] + # Causes an error when an If statement that checks an error variable doesn't + # cuddle with the assignment of that variable. + force-err-cuddling: false + # When force-err-cuddling is enabled this is a list of names + # used for error variables to check for in the conditional. + error-variable-names: [ "err" ] + # Causes an error if a short declaration (:=) cuddles with anything other than + # another short declaration. + # This logic overrides force-err-cuddling among others. + force-short-decl-cuddling: false + +linters: + enable-all: true + disable: + - deadcode # Deprecated, abandoned, replaced by "unused" + - exhaustivestruct # Deprecated, abandoned, replaced by "exhauststruct" + - gocyclo + - golint + - ifshort # Deprecated + - interfacer # Deprecated, abandoned + - maligned # Deprecated, abandoned, replaced by "govet's fieldalignment" + - nosnakecase # Deprecated, abandoned, replaced by revive's var-naming + - prealloc # Unnecessary over-optimization + - scopelint # Deprecated, abandoned, replaced by exportloopref + - structcheck # Deprecated, abandoned, replaced by "unused" + - testpackage # We don't always want to use separate black-box _test package + - varcheck # Deprecated, abandoned, replaced by "unused" + +issues: + # List of regexps of issue texts to exclude. + # + # But independently of this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. + # To list all excluded by default patterns execute `golangci-lint run --help` + # + # Default: https://golangci-lint.run/usage/false-positives/#default-exclusions + exclude: + - abcdef + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + - path: test/mock + linters: + - revive + - path: _test\.go + linters: + - errcheck + - dupl + - funlen + - gosec + - scopelint + - unparam + - gochecknoglobals + - lll + - goconst + - path: test + linters: + - errcheck + - dupl + - gosec + - scopelint + - unparam + # Exclude some staticcheck messages + # - linters: + # - staticcheck + # text: "SA9003:" + # - linters: + # - staticcheck + # text: "SA1012:" + # Exclude lll issues for long lines with go:generate + - linters: + - lll + source: "^//go:generate " + # Independently of option `exclude` we use default exclude patterns, + # it can be disabled by this option. + # To list all excluded by default patterns execute `golangci-lint run --help`. + # Default: true. + exclude-use-default: false + # If set to true exclude and exclude-rules regular expressions become case-sensitive. + # Default: false + exclude-case-sensitive: false + # The list of ids of default excludes to include or disable. + # https://golangci-lint.run/usage/false-positives/#default-exclusions + # Default: [] + include: [] + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 + max-issues-per-linter: 0 + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 0 + # Show only new issues: if there are unstaged changes or untracked files, + # only those changes are analyzed, else only changes in HEAD~ are analyzed. + # It's a super-useful option for integration of golangci-lint into existing large codebase. + # It's not practical to fix all existing issues at the moment of integration: + # much better don't allow issues in new code. + # + # Default: false. + new: false + # Fix found issues (if it's supported by the linter). + fix: true + # Show only new issues created after git revision `REV` + # new-from-rev: REV + # Show only new issues created in git patch with set file path. + # new-from-patch: path/to/patch/file + +severity: + # Set the default severity for issues. + # + # If severity rules are defined and the issues do not match or no severity is provided to the rule + # this will be the default severity applied. + # Severities should match the supported severity names of the selected out format. + # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity + # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#SeverityLevel + # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance + # + # Default value is an empty string. + default-severity: error + # If set to true `severity-rules` regular expressions become case-sensitive. + # Default: false + case-sensitive: true + # When a list of severity rules are provided, severity information will be added to lint issues. + # Severity rules have the same filtering capability as exclude rules + # except you are allowed to specify one matcher per severity rule. + # Only affects out formats that support setting severity information. + # + # Default: [] + rules: + - linters: + - dupl + severity: info diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5bc5288 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +.PHONY: lint +lint: + pkgx golangci-lint@latest run \ No newline at end of file diff --git a/README.md b/README.md index 72efa94..05cbd8d 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,10 @@ our example [**SDL file**][sdl-file] (Schema Definition Language). ### Installing -Eventually, I may package this up in Tea and maybe even Homebrew (via +Eventually, I may package this up in [pkgx][pkgx] and maybe even Homebrew (via [Goreleaser][goreleaser-brew]). +[pkgx]: https://pkgx.sh/ [goreleaser-brew]: https://goreleaser.com/customization/homebrew/ #### With `go install` @@ -72,14 +73,18 @@ docker run --rm \ go run cmd/graphql-schema-picker/main.go \ --debug \ pick \ - --output examples/pruned.sdl.graphqls \ + --config examples/config.toml \ --sdl-file examples/hasura.sdl.graphqls \ - --definitions Aircrafts + --output examples/pruned.sdl.graphqls \ + --definitions Aircrafts,AircraftsInsertInput ``` ### Releasing -Create tags with `xc tag` and push them with `git push --tags`. +Follow [Conventional Commits][conventional-commits] and SemVer releases should +happen automatically via GitHub Actions. + +[conventional-commits]: https://www.conventionalcommits.org/en/v1.0.0/ ## Tasks @@ -88,14 +93,5 @@ Create tags with `xc tag` and push them with `git push --tags`. Builds the Go program into a local binary. ```shell -goreleaser build --clean --single-target -``` - -### tag - -Create a new Git tag - -```shell -sh <(curl https://tea.xyz) +github.com/caarlos0/svu \ - git tag -a $(svu next) -m "$(svu next)" +pkgx goreleaser build --clean --single-target ``` diff --git a/examples/config.toml b/examples/config.toml new file mode 100644 index 0000000..2f6b62e --- /dev/null +++ b/examples/config.toml @@ -0,0 +1,9 @@ +[[type]] +name = "Aircrafts" +new_name = "SvcAircrafts" +deny_list = ["flightsAggregate"] + +[[type]] +name = "AircraftsInsertInput" +new_name = "SvcAircraftsInsertInput" +deny_list = ["airline", "flights", "manufacturer"] \ No newline at end of file diff --git a/go.mod b/go.mod index 80879e3..b8ab29c 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,18 @@ module github.com/kevinmichaelchen/graphql-schema-picker go 1.21.0 require ( + github.com/BurntSushi/toml v1.3.2 github.com/charmbracelet/log v0.3.0 github.com/dominikbraun/graph v0.23.0 github.com/graphql-go/graphql v0.8.1 github.com/spf13/cobra v1.8.0 + github.com/stretchr/testify v1.8.4 ) require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/lipgloss v0.9.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -19,8 +22,10 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/sys v0.13.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c92da03..4c246bb 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= @@ -43,6 +45,7 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQz golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/cli/ast_print.go b/internal/cli/ast_print.go index 2503e60..e0fe36c 100644 --- a/internal/cli/ast_print.go +++ b/internal/cli/ast_print.go @@ -2,10 +2,11 @@ package cli import ( "bufio" + "os" + "github.com/charmbracelet/log" "github.com/graphql-go/graphql/language/ast" "github.com/graphql-go/graphql/language/printer" - "os" ) func printSDL(doc *ast.Document) { diff --git a/internal/cli/cli.go b/internal/cli/cli.go index acd760d..fbb7f08 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -1,9 +1,10 @@ package cli import ( + "os" + "github.com/charmbracelet/log" "github.com/spf13/cobra" - "os" ) var rootCmd = &cobra.Command{ @@ -16,6 +17,11 @@ var rootCmd = &cobra.Command{ if debug { log.SetLevel(log.DebugLevel) } + + err := loadConfig() + if err != nil { + log.Fatal("error occurred while loading config", "err", err) + } }, } @@ -26,6 +32,7 @@ var ( dryRun bool desiredDefinitions []string output string + configPath string ) // LDFlags contain fields that get linked and compiled into the final binary @@ -46,6 +53,7 @@ func init() { pick.Flags().StringSliceVarP(&desiredDefinitions, "definitions", "d", []string{}, "definitions from the SDL you want to pick/keep") pick.Flags().StringVarP(&output, "output", "o", "", "where the resulting schema/SDL file is written") + pick.Flags().StringVarP(&configPath, "config", "c", "", "path to config file") } func Main(ldf LDFlags) { diff --git a/internal/cli/cli_pick.go b/internal/cli/cli_pick.go index d223181..4b10200 100644 --- a/internal/cli/cli_pick.go +++ b/internal/cli/cli_pick.go @@ -1,10 +1,11 @@ package cli import ( + "os" + "github.com/charmbracelet/log" "github.com/dominikbraun/graph/draw" "github.com/spf13/cobra" - "os" ) var pick = &cobra.Command{ diff --git a/internal/cli/cli_version.go b/internal/cli/cli_version.go index ab658db..9edefc5 100644 --- a/internal/cli/cli_version.go +++ b/internal/cli/cli_version.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "github.com/spf13/cobra" ) diff --git a/internal/cli/config.go b/internal/cli/config.go new file mode 100644 index 0000000..025c716 --- /dev/null +++ b/internal/cli/config.go @@ -0,0 +1,49 @@ +package cli + +import ( + "fmt" + "github.com/BurntSushi/toml" +) + +var cfg config + +type config struct { + Types []Type `toml:"type"` +} + +func (c config) toMap() map[string]Type { + out := make(map[string]Type, len(c.Types)) + + for _, t := range c.Types { + out[t.Name] = t + } + + return out +} + +// Type - A GraphQL type in a GraphQL schema. +type Type struct { + // Name - The name of the GraphQL type you want to keep/pick. + Name string `toml:"name"` + + // NewName - The name we should use when creating the new type. + // + // Optional. + // + // This field exists for scenarios where the original/source type cannot be + // removed from the existing GraphQL schema, and you need to come up with a + // new name for your type variant to avoid a name collision. + NewName string `toml:"new_name"` + + // DenyList - List of fields within that type you want to filter out. + DenyList []string `toml:"deny_list"` +} + +func loadConfig() error { + _, err := toml.DecodeFile(configPath, &cfg) + if err != nil { + return fmt.Errorf("unable to decode config: %w", err) + } + + return nil +} diff --git a/internal/cli/config_test.go b/internal/cli/config_test.go new file mode 100644 index 0000000..2372612 --- /dev/null +++ b/internal/cli/config_test.go @@ -0,0 +1,43 @@ +package cli + +import ( + "github.com/BurntSushi/toml" + "github.com/stretchr/testify/require" + "testing" +) + +const blob = ` +[[type]] +name = "PersonInsertInput" +new_name = "SvcPersonInsertInput" +deny_list = ["address"] + +[[type]] +name = "Person" +new_name = "SvcPerson" +deny_list = ["address"] +` + +func TestDecode(t *testing.T) { + var testCfg config + + _, err := toml.Decode(blob, &testCfg) + require.NoError(t, err) + + expected := config{ + Types: []Type{ + { + Name: "PersonInsertInput", + NewName: "SvcPersonInsertInput", + DenyList: []string{"address"}, + }, + { + Name: "Person", + NewName: "SvcPerson", + DenyList: []string{"address"}, + }, + }, + } + + require.Equal(t, expected, testCfg) +} diff --git a/internal/cli/def_filter.go b/internal/cli/def_filter.go new file mode 100644 index 0000000..f929117 --- /dev/null +++ b/internal/cli/def_filter.go @@ -0,0 +1,117 @@ +package cli + +import ( + "github.com/charmbracelet/log" + "github.com/graphql-go/graphql/language/ast" + "github.com/graphql-go/graphql/language/kinds" +) + +// filters fields out of a GraphQL type definition +func filterDef(def Vertex) ast.Node { + var out ast.Node + + node := def.Node + + switch node.GetKind() { + case kinds.ObjectDefinition: + obj := node.(*ast.ObjectDefinition) + objName := obj.Name.Value + + newObjName := getNewObjectName(objName) + log.Info("newObjName", "newObjName", newObjName) + + var fields []*ast.FieldDefinition + for _, field := range obj.Fields { + fieldName := field.Name.Value + + if isFilteredField(objName, fieldName) { + continue + } + + fields = append(fields, field) + } + + out = &ast.ObjectDefinition{ + Kind: obj.Kind, + // Location might not be accurate since we're pruning, so exclude it + Loc: obj.Loc, + Name: &ast.Name{ + Kind: kinds.Name, + Loc: obj.Name.Loc, + Value: newObjName, + }, + Description: obj.Description, + // TODO we don't support interface pruning - + // if we prune a field on the interface, we'd have to prune the + // interface as well - not sure how to handle that yet + Interfaces: nil, + Directives: obj.Directives, + Fields: fields, + } + + log.Debug("Returning new ObjectDefinition", "name", newObjName) + + case kinds.InputObjectDefinition: + obj := node.(*ast.InputObjectDefinition) + objName := obj.Name.Value + + newObjName := getNewObjectName(objName) + + var fields []*ast.InputValueDefinition + for _, field := range obj.Fields { + fieldName := field.Name.Value + + if isFilteredField(objName, fieldName) { + continue + } + + fields = append(fields, field) + } + + out = &ast.InputObjectDefinition{ + Kind: obj.Kind, + // Location might not be accurate since we're pruning, so exclude it + Loc: obj.Loc, + Name: &ast.Name{ + Kind: kinds.Name, + Loc: obj.Name.Loc, + Value: newObjName, + }, + Description: obj.Description, + Directives: obj.Directives, + Fields: fields, + } + + log.Debug("Returning new InputObjectDefinition", "name", newObjName) + + default: + return node + } + + return out +} + +func getNewObjectName(objName string) string { + typeMap := cfg.toMap() + log.Info("looking for object name", "objName", objName, "typeMap", typeMap) + defCfg := typeMap[objName] + if defCfg.NewName != "" { + return defCfg.NewName + } + + return defCfg.Name +} + +// isFilteredField - Checks if the field should be filtered out +func isFilteredField(objName, fieldName string) bool { + defCfg := cfg.toMap()[objName] + denyList := defCfg.DenyList + + for _, e := range denyList { + if fieldName == e { + return true + } + } + + return false +} diff --git a/internal/cli/graph.go b/internal/cli/graph.go index 88e7f0f..a085965 100644 --- a/internal/cli/graph.go +++ b/internal/cli/graph.go @@ -1,11 +1,12 @@ package cli import ( + "strings" + "github.com/charmbracelet/log" "github.com/dominikbraun/graph" "github.com/graphql-go/graphql/language/ast" "github.com/graphql-go/graphql/language/kinds" - "strings" ) type Vertex struct { @@ -17,7 +18,14 @@ type Describer interface { GetDescription() *ast.StringValue } -func sanitizeComment(d Describer) string { +func sanitizeComment(d Describer) *ast.StringValue { + return &ast.StringValue{ + Kind: kinds.StringValue, + Value: sanitizeCommentText(d), + } +} + +func sanitizeCommentText(d Describer) string { desc := d.GetDescription() if desc == nil { return "" @@ -28,6 +36,7 @@ func sanitizeComment(d Describer) string { func NewVertex(node ast.Node) Vertex { var name string + switch node.GetKind() { case kinds.ScalarDefinition: obj := node.(*ast.ScalarDefinition) @@ -35,10 +44,7 @@ func NewVertex(node ast.Node) Vertex { // Sanitize description (e.g., remove double-quotes) if obj.Description != nil { - obj.Description = &ast.StringValue{ - Kind: kinds.StringValue, - Value: sanitizeComment(obj), - } + obj.Description = sanitizeComment(obj) } case kinds.InterfaceDefinition: obj := node.(*ast.InterfaceDefinition) @@ -46,10 +52,7 @@ func NewVertex(node ast.Node) Vertex { // Sanitize description (e.g., remove double-quotes) if obj.Description != nil { - obj.Description = &ast.StringValue{ - Kind: kinds.StringValue, - Value: sanitizeComment(obj), - } + obj.Description = sanitizeComment(obj) } case kinds.UnionDefinition: obj := node.(*ast.UnionDefinition) @@ -57,10 +60,7 @@ func NewVertex(node ast.Node) Vertex { // Sanitize description (e.g., remove double-quotes) if obj.Description != nil { - obj.Description = &ast.StringValue{ - Kind: kinds.StringValue, - Value: sanitizeComment(obj), - } + obj.Description = sanitizeComment(obj) } case kinds.EnumDefinition: obj := node.(*ast.EnumDefinition) @@ -68,10 +68,7 @@ func NewVertex(node ast.Node) Vertex { // Sanitize description (e.g., remove double-quotes) if obj.Description != nil { - obj.Description = &ast.StringValue{ - Kind: kinds.StringValue, - Value: sanitizeComment(obj), - } + obj.Description = sanitizeComment(obj) } case kinds.InputObjectDefinition: obj := node.(*ast.InputObjectDefinition) @@ -79,10 +76,7 @@ func NewVertex(node ast.Node) Vertex { // Sanitize description (e.g., remove double-quotes) if obj.Description != nil { - obj.Description = &ast.StringValue{ - Kind: kinds.StringValue, - Value: sanitizeComment(obj), - } + obj.Description = sanitizeComment(obj) } case kinds.ObjectDefinition: @@ -91,15 +85,14 @@ func NewVertex(node ast.Node) Vertex { // Sanitize description (e.g., remove double-quotes) if obj.Description != nil { - obj.Description = &ast.StringValue{ - Kind: kinds.StringValue, - Value: sanitizeComment(obj), - } + obj.Description = sanitizeComment(obj) } default: panic("NewVertex: unsupported node kind: " + node.GetKind()) } + log.Debug("Creating vertex", "name", name) + return Vertex{ Name: name, Node: node, @@ -124,7 +117,7 @@ func buildPrunedGraph(doc *ast.Document) graph.Graph[string, Vertex] { // Build edges between vertices. buildEdges(g) - // Prunes any vertices that don't appear in any edges + // Prune out any GraphQL types and fields that we don't want return prune(g) } @@ -153,21 +146,28 @@ func loadTopLevelDefinitions(g graph.Graph[string, Vertex], doc *ast.Document) { } } +// Prune our graph: +// 1. We filter out any vertices (GQL types) that we don't explicitly want +// 2. We filter out any fields within those GQL types func prune(in graph.Graph[string, Vertex]) graph.Graph[string, Vertex] { - m, err := in.AdjacencyMap() + adjacencyMap, err := in.AdjacencyMap() if err != nil { log.Fatal("unable to retrieve adjacency map", "err", err) } out := graph.New(VertexHash) - for defName, edges := range m { + for defName, edges := range adjacencyMap { if !isDesired(defName) { continue } + // Retrieve the vertex (GraphQL type) by its name def := must(in.Vertex(defName)) - // Add vertex + // Clone the GraphQL type definition and perform field filtering + def = NewVertex(filterDef(def)) + + // Add vertex (GraphQL type) to our new, outgoing graph _ = out.AddVertex(def) // Add its dependent vertices @@ -189,6 +189,7 @@ func must(v Vertex, err error) Vertex { } func isDesired(definitionName string) bool { + // TODO deprecate in favor of config for _, d := range desiredDefinitions { if definitionName == d { return true @@ -199,6 +200,7 @@ func isDesired(definitionName string) bool { } func isBasicType(t string) bool { + // https://graphql.org/graphql-js/basic-types/ return t == "String" || t == "Float" || t == "Int" || t == "Boolean" || t == "ID" } diff --git a/internal/cli/graph_edges.go b/internal/cli/graph_edges.go index 21746a1..74bbe5f 100644 --- a/internal/cli/graph_edges.go +++ b/internal/cli/graph_edges.go @@ -2,6 +2,7 @@ package cli import ( "errors" + "github.com/charmbracelet/log" "github.com/dominikbraun/graph" "github.com/graphql-go/graphql/language/ast" diff --git a/test/schema.graphql b/test/schema.graphql index 9eb3c92..8aea402 100644 --- a/test/schema.graphql +++ b/test/schema.graphql @@ -12,4 +12,14 @@ Representation of a "Bar type Bar { name: String quantity: Int! +} + +input FooInsertInput { + name: String + bar: BarInsertInput +} + +input BarInsertInput { + name: String + quantity: Int! } \ No newline at end of file