GitHub - oakmac/standard-clojure-style-js: Standard Clojure Style in JavaScript (original) (raw)

A JavaScript library to format Clojure code according to Standard Clojure Style.

Introduction and Demo

I gave a 10-minute lightning talk at Clojure/conj 2024 about this project:

Introduction to Standard Clojure Style video preview

Project Background and Rationale

Please see Issue #1 for an explanation of this project's genesis.

Standard Clojure Style aspires to be the obvious, boring choice for formatting Clojure source code.

Try it online for free right now!

Try online using Squint playground.

No purchase necessary. Side effects may include formatted Clojure code, sudden urges to REPL, and a strange satisfaction of consistently formatted namespaces. Not responsible for increased productivity due to reduced bikeshedding with coworkers.

I want YOU for testing 🤠

Calling all adventurous Clojure developers! Please run this library on your codebase and report bugs.

go to a Clojure project directory

cd your-clojure-project/

IMPORTANT: check out a clean git branch so you can revert any changes made by the tool

git checkout -b standard-clj-testing

run it!

NOTE: your directory names may be different, please adjust accordingly

npx @chrisoakman/standard-clojure-style check src-clj/ src-cljs/ test/

npx @chrisoakman/standard-clojure-style fix src-clj/ src-cljs/ test/

See the Command Line Usage section below for more options.

Please open an issue if Standard Clojure Style breaks your code 🙃

Editor Integrations and Other Implementations

It is a goal of Standard Clojure Style to "meet you where you are". ie: in your editor, on the web, CLI tooling, etc.

Editor Integrations

Implementations in Other Programming Languages

Project Status and Stability

As of April 2025, this formatter is ready for most Clojure codebases. There are still some outstanding bugs that I want to fix before releasing v1.0.0, but I do not want this project to live in "pre-1.0" forever.

Command Line Usage

The @chrisoakman/standard-clojure-style npm package exposes a command-line tool to help format your Clojure projects. You may wish to run this as a git hook, via continuous integration, an editor integration, etc.

If you have Node.js installed on your system, you can try out Standard Clojure Style with the npx command:

NOTE: the "fix" command will change your files on disk!

Please ensure a clean git working tree or new branch as necessary

formats the file located at src/com/example/foo.clj

npx @chrisoakman/standard-clojure-style fix src/com/example/foo.clj

formats all .clj, .cljs, .cljc, .jank, .edn files found in the src/ directory

and subdirectories (ie: recursive)

npx @chrisoakman/standard-clojure-style fix src/

If you plan to use the library frequently you may wish to install it globally:

Installs "standard-clj" globally onto your system via npm

npm install --global @chrisoakman/standard-clojure-style

Quick Reference

use the "list" command to see which files standard-clj will analyze

standard-clj list src/

use the "check" command to see which files need formatting

standard-clj check src-clj/ src-cljs/

use the "fix" command to format files with Standard Clojure Style

standard-clj fix src/ test/ project.clj

you can pass a glob pattern for more control over which files are formatted

standard-clj fix --include "src/**/*.{clj,cljs,cljc}"

ignore files or folders with the --ignore flag

standard-clj fix --include "src/**/*.{clj,cljs,cljc}" --ignore "src/com/example/some_weird_file.clj"

standard-clj will look for a .standard-clj.edn or .standard-clj.json file in the directory where

the command is run from (likely the root directory for your project)

echo '{:include ["src-clj//*.clj" "src-cljs//*.cljs"]}' > .standard-clj.edn standard-clj fix

or pass a config file explicitly using the --config argument

standard-clj list --config /home/user1/my-project/my-standard-cfg.json

pipe code directly to the fix command using "-"

echo '(ns my.company.core (:require [clojure.string :as str]))' | standard-clj fix -

list command

Use standard-clj list to see which files will be effected by the check andfix commands. This command is useful in order to test your --includeglob patterns or .standard-clj.edn config files.

prints each filename that will be effected by the "check" and "fix" commands

standard-clj list src/

output the same file list in various data formats

standard-clj list src/ --output json standard-clj list src/ --output json-pretty standard-clj list src/ --output edn standard-clj list src/ --output edn-pretty

check command

Use standard-clj check to see if files are already formatted with Standard Clojure Style. Useful for continuous integration. This command will not write to any files on disk.

Returns exit code 0 if all files are already formatted, 1 otherwise.

check to see if files are already formatted with Standard Clojure Style

standard-clj check src-clj/ src-cljs/ test/

runs the same check, but only prints files that need fixing

standard-clj check src-clj/ src-cljs/ test/ --log-level=ignore-already-formatted

fix command

Use standard-clj fix to format files according to Standard Clojure Style. This command will write to files on disk, so please ensure a clean git working tree or new branch as necessary. The changes made by this command cannot be undone by this program.

Returns exit code 0 if all files have been formatted, 1 otherwise.

format files according to Standard Clojure Style

standard-clj fix src/ test/ deps.edn

fix - command (stdin / stdout)

Use standard-clj fix - to pipe code directly via stdin.

Prints the formatted code to stdout with error code 0 if successful. Prints an error message to stderr with error code 1 otherwise.

echo '(ns my.company.core (:require [clojure.string :as str]))' | standard-clj fix -

Which files will be formatted?

standard-clj accepts several ways to know which files to format:

will fix:

- dev/user.clj (single file argument)

- project.clj (single file argument)

- all .clj, .cljs, .cljc, .edn files in the src-clj/ directory and subdirectories (directory argument)

- all .edn files in the resources/ directory and subdirectories (glob pattern argument)

standard-clj fix dev/user.clj project.clj src-clj/ test/ --include "resources/**/*.edn"

--include or --ignore arguments passed via command line will supercede any--include or --ignore arguments found via config file.

You can always use the list command to see which files will be formatted by standard-clj.

Other options

Options via config file

By default, standard-clj will look for a .standard-clj.edn or.standard-clj.json file located in the directory where the command is run. Most projects that use standard-clj regularly will want to commit this file to their git repo for convenience.

create a .standard-clj.edn file

echo '{:include ["src-clj//*.clj" "src-cljs//*.cljs"]}' > .standard-clj.edn

run the "fix" command with options from that file

standard-clj fix

You can use the --config or -c flag to specify a different file location:

run the "fix" command with options from ./my-config-file.edn

standard-clj fix --config ./my-config-file.edn

Ignore a file or form

You can instruct Standard Clojure Style to ignore the next form by using #_:standard-clj/ignore

#_:standard-clj/ignore [:the :formatter :will :ignore

:me

]

Or ignore an entire file by placing #_:standard-clj/ignore-file before the (ns) form.

#_:standard-clj/ignore-file

(ns com.example.some-weird-file)

;; ...

Please note that #_:standard-clj/ignore will not work inside of the ns form, but it can be used to tell Standard Clojure Style to "ignore the ns form entirely":

;; this will NOT work

(ns com.example.my-app (:require #_:standard-clj/ignore [clojure.string :as string]))

;; this WILL work

#_:standard-clj/ignore (ns com.example.my-app (:require [clojure.string :as string]))

It is recommended to use #_:standard-clj/ignore sparingly, and ideally not at all. However, there are always edge case exceptions where it makes sense to ignore formatting.

I recommend ignoring whole forms at the top-level (ie: forms that start on column 0, like defn or ns), instead of "some formatted outside, some ignored inside".

;; recommended, sparingly:

#_:standard-clj/ignore (defn some-weird-fn [] ...)

;; not recommended:

(defn some-weird-fn [] (let [a "a" b "b"] #_:standard-clj/ignore ...))

Creating a binary

Bun has a neat feature where you can create an executable binary from JavaScript source:

create a binary for Standard Clojure Style

bun build ./cli.mjs --compile --outfile standard-clj

run your binary

./standard-clj check /home/user1/my-project/src

move the binary to somewhere on your path

mv standard-clj /usr/local/bin

Formatting Rules

NOTE: this is an incomplete list. I am working on a website that will document all of the formatting rules. 20 Sep 2024

Things that Standard Clojure Style does NOT do

References

Coding Style

The coding style for this library is intentionally very simple in order to make porting the algorithm to multiple languages easier. This is informed by my experience porting parinfer.js to multiple languages (parinfer-lua, parinfer.py, and others).

Here are some rules to follow:

Note: this should not be considered a definitive list. I will add to this as I come across additional cases.

Development

Make sure that either Node.js or bun are installed (both should work).

run unit tests

bun test

test a single file

bun run jest format.test.js

lint JS

bun run lint

Notes / Misc

License

ISC License