Skip to content

Configuration

Every setting is optional. The table below lists each setting and its default value. The YAML block shows all available keys; some values are examples.

defaults:
  unexported: private     # shared | private

rules:
  naming:
    qualify: never        # always | never | ondemand
    exported: false       # true | false
    vocabulary:
      mouse: [wheel]
  boundary: on           # off | on
  surplus: strict        # off | loose | strict
  unused: strict         # off | loose | strict

filter:
  only: []              # nothing outside these, when set
  omit:
    - "**/mock_*.go"    # and not these

baseline: .declscope-baseline.yaml
Key Values Default Effect
defaults.unexported shared, private private Scope of a declaration that carries no directive and inherits none
rules.naming.qualify always, never, ondemand never When a name must carry its namespace. See the naming rule
rules.naming.exported true, false false Whether the naming rule also reaches exported declarations. The rename is never offered there
rules.naming.vocabulary Namespace to a list of words None Extra words that carry a namespace. See what carries a namespace
rules.boundary off, on on Whether the boundary rule reports. See reach without a boundary
rules.surplus off, loose, strict strict How much the surplus rule reports. See strict
rules.unused off, loose, strict strict How much the unused rule reports. See off, loose and strict
filter.only Path globs None When set, no file outside them is read. Empty places no restriction
filter.omit Path globs None Files taken back out, whether or not only let them through
baseline A path relative to the config file The nearest .declscope-baseline.yaml The baseline to consult

Tip

For the recommended checks, put this in .declscope.yaml:

rules:
  naming:
    qualify: ondemand
    exported: true

ondemand checks names once a package has a second namespace. exported: true includes exported declarations. surplus and unused default to strict.

  • The file is .declscope.yaml or .declscope.yml. An empty one changes nothing.
  • -config names one file, and reads no other.
  • An unknown key is an error, and so is a value a key does not accept. The message names what the section does take, so a typo never leaves a rule at its default in silence.

defaults takes only unexported, because an exported declaration has no scope to default.

How two config files compose

Every .declscope.yaml between the analyzed package and the module root is read, outermost first. A nearer file does not replace the one above it. Each key composes on its own.

Key Down the chain
defaults.*, rules.* except vocabulary, baseline The nearest file that states the key wins. A key no file states takes the built-in default
rules.naming.vocabulary Merged per namespace. The nearer file wins the namespaces it states
filter.only Intersected. A file is read when it matches every stating file's list
filter.omit Unioned. A file matching any level's list is not read

Important

A config file can only ever shrink what is read. An omit written at the root holds everywhere below it, and no nested file can undo it. filter has no negation, so nothing like .gitignore's ! can put a path back.

The filter rule

filter decides which files are read at all. A file matches a list when it matches any pattern in it.

Written Read
Neither Every file
only alone Nothing outside the patterns
omit alone Everything except the patterns
Both What only admits, minus what omit names

An empty only places no restriction, which is why a repository with no config is read whole.

A pattern is read against the directory of the config file that states it. Anchoring follows the rules of .gitignore.

Pattern Matches
gen.go A file of that name at any depth
/gen.go, ./gen.go The one beside this config file
gen/** That directory beside this config file, and no other
**/gen/** That directory at any depth
gen/ That directory at any depth, the same as **/gen/**
/gen/, ./gen/ That directory beside this config file, the same as gen/**
*, ? Within one path segment

A leading ./ anchors the same way as a leading /. A trailing / names a directory and everything in it. Without one, a pattern names a file, so ./vendor matches only a file called vendor. Write ./vendor/ or ./vendor/** for the directory.

One report comes from the configuration rather than from the code. It fires when a file's only matches files, but an only above it removes them all, so the package is read as empty.

sub/a.go:1:1: filter.only stated in /repo/sub matches 1 file(s) here, but an only above it removes them all, so this package is read as empty

The report is that narrow on purpose. A package that reads nothing is usually the point, as with a root only naming one subtree, or an omit naming a directory.

The cause is in the config files, so fix it there: change the nested only, or the only above it, so that the files are read. No directive silences this report, since nothing in the package is read. filter is still a valid rule name for //declscope:ignore, but such an ignore silences nothing, so the unused rule reports it.