Skip to content

An efficient, smart, graceful composition of Clojure formatters, linters and such.

License

Notifications You must be signed in to change notification settings

nedap/formatting-stack

Repository files navigation

formatting-stack CircleCI

formatting-stack is a formatting/linting solution that can be integrated with:

  • your Component (or Integrant, or bare tools.namespace) system
    • for instantaneous performance
      • no cold-starts!
    • and precise understanding of your codebase
      • powered by Clojure's introspection capabilities (reified vars, namespaces), and occasionally eval
    • and a reasonable triggering frequency
      • so you don't format too frequently (format-on-save), or not frequently enough (git pre-commit hook)
  • Git status/branch information
    • for some performance gains (typically only added/changed files will be processed)
    • and also for gradual formatting
  • Anything you want
    • A vanilla repl, Lein task, CI workflow...

As of today, it is integrated with:

And it also bundles a few tiny linters of its own:

It is fully extensible: you can configure the bundled formatters, remove them, and/or add your own.

Whenever it's safe, each formatter/linter will make full use of your CPU's cores.

Linters' reports are presented under a unified format.

Smart code analysis

As mentioned, formatting-stack understands your codebase and its dependencies. It knows which vars in the project are macros. It also reads the metadata of all function/macro vars.

It also associates :style metadata to your project's vars, in a clean manner, when needed.

Armed with those powers, we can do two nifty things:

  • Inform cljfmt of indentation through metadata + config, using the CIDER indent spec format (by default, using an heuristic for cider->cljfmt format translation) or the cljfmt format (as a fallback).
    • Recommendation: use metadata for your own code, use config for third-party code (that may be awaiting for a pull request)
  • Inform CIDER of indentation rules through config
    • CIDER understands either metadata or emacs-specific rules, but not config

You can find examples of how to do such configuration in the wiki.

Graceful git strategies

Git integration is documented at formatting-stack.strategies.

The general intent is to make formatting:

  • Efficient
    • don't process non-touched files
  • Gradual
    • don't format the whole project at once
    • favor reviewable diffs - nobody can review (or learn from) whole-project diffs
  • Safe
    • only format code that is completely staged by git
      • else any bug in formatting code could destroy your unsaved changes

...that's the default Git strategy anyway, apt for repl-driven development. You are free to supply an alternative strategy.

Commonly needed alternative strategies are offered/documented in branch-formatter and project-formatter.

Consolidated reporting

As you can see in the screenshot, formatting-stack presents linters' outputs under a hierarchical, file-grouped format.

Screenshot 2020-02-19 at 07 04 38

Alternative reporters can be found in ./src/formatting_stack/reporters, such as

  • formatting-stack.pretty-line-printer offers more concise output
  • formatting-stack.file-writer offers a file-output instead of stdout

Installation

Coordinates

[formatting-stack "4.6.0"]

Also you might have to add the refactor-nrepl dependency.

  • If you use tooling like CIDER, typically this dependency will be already injected into your classpath, so no action required in this case.
  • Else, please add the latest version to your project (or personal profile).
  • If this dependency isn't added, formatting-stack will degrade gracefully, using slightly fewer formatters/linters.

Reloaded Workflow integration

  • If you use the Component component, then com.stuartsierra.component.repl/reset will use formatting-stack, applying all its formatters/linters.
  • If you use the Integrant component, then integrant.repl/reset will use formatting-stack, applying all its formatters/linters.

The above can be good enough. However resetting your system can be somewhat expensive, and you may find yourself using clojure.tools.namespace.repl/refresh instead.

For that case, you can create some facility (e.g. shortcut, snippet) for the following code:

(clojure.tools.namespace.repl/refresh :after 'formatting-stack.core/format!)

Vanilla integration

formatting-stack.core/format! is a plain function, considered a public API, that is safe to invoke over REPL, a script, or anything you please.

See also: format-and-lint-branch!, format-and-lint-project!.

Advanced configuration

If you want to add custom members to the format! options (namely: :formatters, or :strategies, etc), a typical pattern would be:

(formatting-stack.core/format! :formatters (conj formatting-stack.defaults/default-formatters my-custom-formatter))

You can also pass [] for disabling a particular aspect:

;; The default :formatters will be used, no :linters will be run:
(formatting-stack.core/format! :linters [])

...And you can also override specific parameters (like max line length from 130 to 80) in a fine-grained manner, as documented in customization_example.clj.

License

Copyright © Nedap

This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0.

About

An efficient, smart, graceful composition of Clojure formatters, linters and such.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •