{"id":17070477,"url":"https://github.com/oakmac/standard-clojure-style-js","last_synced_at":"2025-04-04T16:09:07.889Z","repository":{"id":226458767,"uuid":"636958085","full_name":"oakmac/standard-clojure-style-js","owner":"oakmac","description":"Standard Clojure Style in JavaScript","archived":false,"fork":false,"pushed_at":"2025-03-05T13:51:21.000Z","size":1193,"stargazers_count":104,"open_issues_count":36,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-28T15:03:56.755Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oakmac.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-06T04:42:03.000Z","updated_at":"2025-03-19T16:57:39.000Z","dependencies_parsed_at":"2024-03-07T18:03:47.983Z","dependency_job_id":"d2784097-b41d-4106-a83e-55669ac633c0","html_url":"https://github.com/oakmac/standard-clojure-style-js","commit_stats":{"total_commits":217,"total_committers":2,"mean_commits":108.5,"dds":0.004608294930875556,"last_synced_commit":"f2229bb851275cf503fbe8107a1b6f266a84fff7"},"previous_names":["oakmac/clojurefmt-js","oakmac/standard-clojure-style-js"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakmac%2Fstandard-clojure-style-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakmac%2Fstandard-clojure-style-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakmac%2Fstandard-clojure-style-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakmac%2Fstandard-clojure-style-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oakmac","download_url":"https://codeload.github.com/oakmac/standard-clojure-style-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247208143,"owners_count":20901570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T11:31:41.408Z","updated_at":"2025-04-04T16:09:07.844Z","avatar_url":"https://github.com/oakmac.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Standard Clojure Style [![npm](https://img.shields.io/npm/v/@chrisoakman/standard-clojure-style)](https://www.npmjs.com/package/@chrisoakman/standard-clojure-style) [![ISC License](https://img.shields.io/npm/l/@chrisoakman/standard-clojure-style)](https://github.com/oakmac/standard-clojure-style-js/blob/master/LICENSE.md)\n\nA JavaScript library to format Clojure code according to Standard Clojure Style.\n\n## Introduction and Demo\n\nI gave a 10-minute lightning talk at [Clojure/conj 2024] about this project:\n\n\u003ca href=\"http://www.youtube.com/watch?feature=player_embedded\u0026v=VhjxvEabOX0\n\" target=\"_blank\"\u003e\u003cimg src=\"http://img.youtube.com/vi/VhjxvEabOX0/0.jpg\"\nalt=\"Introduction to Standard Clojure Style video preview\" width=\"260\" height=\"195\" border=\"10\" /\u003e\u003c/a\u003e\n\n[Clojure/conj 2024]:https://2024.clojure-conj.org/\n\n## Try it online for free right now!\n\n[Try online using Squint playground.](https://tinyurl.com/43abayj2)\n\n\u003e No purchase necessary. Side effects may include formatted Clojure code, sudden\n  urges to REPL, and a strange satisfaction of consistently formatted namespaces.\n  Not responsible for increased productivity due to reduced bikeshedding with coworkers.\n\n## I want YOU for testing :cowboy_hat_face:\n\nCalling all adventurous Clojure developers! Please run this library on your codebase and report bugs.\n\n```sh\n# go to a Clojure project directory\ncd your-clojure-project/\n\n# IMPORTANT: check out a clean git branch so you can revert any changes made by the tool\ngit checkout -b standard-clj-testing\n\n# run it!\n# NOTE: your directory names may be different, please adjust accordingly\nnpx @chrisoakman/standard-clojure-style check src-clj/ src-cljs/ test/\n\nnpx @chrisoakman/standard-clojure-style fix src-clj/ src-cljs/ test/\n```\n\nSee the **Command Line Usage** section below for more options.\n\nPlease [open an issue] when Standard Clojure Style breaks your code :upside_down_face:\n\n[open an issue]:https://github.com/oakmac/standard-clojure-style-js/issues/new\n\n## Project Background and Rationale\n\nPlease see [Issue #1] for an explanation of this project's genesis.\n\n[Issue #1]:https://github.com/oakmac/standard-clojure-style-js/issues/1\n\n## Editor Integrations and Other Implementations\n\nIt is a goal of Standard Clojure Style to \"meet you where you are\". ie: in\nyour editor, on the web, CLI tooling, etc.\n\n### Editor Integrations\n\n- Example Emacs usage [in this post](https://x.com/ovstoica/status/1854192289498706012)\n- [Neovim plugin](https://git.sr.ht/~ioiojo/standard-clojure-style.nvim)\n\n### Implementations in Other Programming Languages\n\n- [Standard Clojure Style in Lua]\n- a port in pure Java is almost ready as of Feb 2025\n- a Python port is planned as of Nov 2024\n\n[Standard Clojure Style in Lua]:https://github.com/oakmac/standard-clojure-style-lua/tree/master\n\n## Project Status and Stability\n\nAs of Nov 2024, I think this formatter is ready for **most** Clojure\ncodebases. There are still [some outstanding bugs] that I want to fix before\nreleasing v1.0.0, but I do not want this project to live in \"pre-1.0\"\nforever.\n\n[some outstanding bugs]:https://github.com/oakmac/standard-clojure-style-js/labels/v1%20blocker\n\n## Command Line Usage\n\nThe `@chrisoakman/standard-clojure-style` npm package exposes a command-line\ntool to help format your Clojure projects. You may wish to run this as a git\nhook, via continuous integration, an editor integration, etc.\n\nIf you have Node.js installed on your system, you can try out Standard Clojure\nStyle with the `npx` command:\n\n```sh\n## NOTE: the \"fix\" command will change your files on disk!\n## Please ensure a clean git working tree or new branch as necessary\n\n# formats the file located at src/com/example/foo.clj\nnpx @chrisoakman/standard-clojure-style fix src/com/example/foo.clj\n\n# formats all .clj, .cljs, .cljc, .jank, .edn files found in the src/ directory\n# and subdirectories (ie: recursive)\nnpx @chrisoakman/standard-clojure-style fix src/\n```\n\nIf you plan to use the library frequently you may wish to install it globally:\n\n```sh\n# Installs \"standard-clj\" globally onto your system via npm\nnpm install --global @chrisoakman/standard-clojure-style\n```\n\n#### Quick Reference\n\n```sh\n# use the \"list\" command to see which files standard-clj will analyze\nstandard-clj list src/\n\n# use the \"check\" command to see which files need formatting\nstandard-clj check src-clj/ src-cljs/\n\n## use the \"fix\" command to format files with Standard Clojure Style\nstandard-clj fix src/ test/ project.clj\n\n## you can pass a glob pattern for more control over which files are formatted\nstandard-clj fix --include \"src/**/*.{clj,cljs,cljc}\"\n\n## ignore files or folders with the --ignore flag\nstandard-clj fix --include \"src/**/*.{clj,cljs,cljc}\" --ignore \"src/com/example/some_weird_file.clj\"\n\n## standard-clj will look for a .standard-clj.edn or .standard-clj.json file in the directory where\n## the command is run from (likely the root directory for your project)\necho '{:include [\"src-clj/**/*.clj\" \"src-cljs/**/*.cljs\"]}' \u003e .standard-clj.edn\nstandard-clj fix\n\n## or pass a config file explicitly using the --config argument\nstandard-clj list --config /home/user1/my-project/my-standard-cfg.json\n\n## pipe code directly to the fix command using \"-\"\necho '(ns my.company.core (:require [clojure.string :as str]))' | standard-clj fix -\n```\n\n#### `list` command\n\nUse `standard-clj list` to see which files will be effected by the `check` and\n`fix` commands. This command is useful in order to test your `--include`\nglob patterns or `.standard-clj.edn` config files.\n\n```sh\n# prints each filename that will be effected by the \"check\" and \"fix\" commands\nstandard-clj list src/\n\n# output the same file list in various data formats\nstandard-clj list src/ --output json\nstandard-clj list src/ --output json-pretty\nstandard-clj list src/ --output edn\nstandard-clj list src/ --output edn-pretty\n```\n\n#### `check` command\n\nUse `standard-clj check` to see if files are already formatted with Standard\nClojure Style. Useful for continuous integration. This command will **not** write\nto any files on disk.\n\nReturns exit code 0 if all files are already formatted, 1 otherwise.\n\n```sh\n# check to see if files are already formatted with Standard Clojure Style\nstandard-clj check src-clj/ src-cljs/ test/\n\n# runs the same check, but only prints files that need fixing\nstandard-clj check src-clj/ src-cljs/ test/ --log-level=ignore-already-formatted\n```\n\n#### `fix` command\n\nUse `standard-clj fix` to format files according to Standard Clojure Style.\nThis command **will** write to files on disk, so please ensure a clean git\nworking tree or new branch as necessary. The changes made by this command\ncannot be undone by this program.\n\nReturns exit code 0 if all files have been formatted, 1 otherwise.\n\n```sh\n# format files according to Standard Clojure Style\nstandard-clj fix src/ test/ deps.edn\n```\n\n#### `fix -` command (stdin / stdout)\n\nUse `standard-clj fix -` to pipe code directly via stdin.\n\nPrints the formatted code to stdout with error code 0 if successful. Prints an\nerror message to stderr with error code 1 otherwise.\n\n```sh\necho '(ns my.company.core (:require [clojure.string :as str]))' | standard-clj fix -\n```\n\n#### Which files will be formatted?\n\n`standard-clj` accepts several ways to know which files to format:\n\n* pass filenames directly as arguments\n* pass directories directly as arguments\n* pass a [glob pattern] with the `--include` option\n\n```sh\n# will fix:\n# - dev/user.clj (single file argument)\n# - project.clj (single file argument)\n# - all .clj, .cljs, .cljc, .edn files in the src-clj/ directory and subdirectories (directory argument)\n# - all .edn files in the resources/ directory and subdirectories (glob pattern argument)\nstandard-clj fix dev/user.clj project.clj src-clj/ test/ --include \"resources/**/*.edn\"\n```\n\n`--include` or `--ignore` arguments passed via command line will supercede any\n`--include` or `--ignore` arguments found via config file.\n\nYou can always use the `list` command to see which files will be formatted by `standard-clj`.\n\n#### Other options\n\n- `--config` or `-c` - pass a filepath of a config file to use for options to the `standard-clj` program.\n- `--ignore` or `-ig` - exclude files from `list`, `check`, or `fix` commands. Accepts individual files or directories.\n- `--include` or `-in` - include files for the `list`, `check`, or `fix` commands. Accepts a [glob pattern].\n- `--log-level` or `-l` - specify a logging level\n  - `\"everything\"` or `0` - prints everything to either stdout or stderr. This is the default.\n  - `\"ignore-already-formatted\"` or `1`\n    - For the `check` command, will only print files that need formatting.\n    - For the `fix` command, will only print files that were formatted or have errors.\n    - This option can be less noisy in your terminal if you have a project with many files and only\n      want to see the ones that need formatting.\n  - `\"quiet\"` or `5` - will not print anything to stdout or stderr for the `check` or `fix` commands\n\n[glob pattern]:https://github.com/isaacs/node-glob?tab=readme-ov-file#glob-primer\n\n#### Options via config file\n\nBy default, `standard-clj` will look for a `.standard-clj.edn` or\n`.standard-clj.json` file located in the directory where the command is run.\nMost projects that use `standard-clj` regularly will want to commit this file\nto their git repo for convenience.\n\n```sh\n# create a .standard-clj.edn file\necho '{:include [\"src-clj/**/*.clj\" \"src-cljs/**/*.cljs\"]}' \u003e .standard-clj.edn\n\n# run the \"fix\" command with options from that file\nstandard-clj fix\n```\n\nYou can use the `--config` or `-c` flag to specify a different file location:\n\n```sh\n# run the \"fix\" command with options from ./my-config-file.edn\nstandard-clj fix --config ./my-config-file.edn\n```\n\n## Ignore a file or form\n\nYou can instruct Standard Clojure Style to ignore the next form by using `#_:standard-clj/ignore`\n\n```clj\n#_:standard-clj/ignore\n    [:the\n:formatter\n  :will    :ignore\n\n :me\n\n]\n```\n\nOr ignore an entire file by placing `#_:standard-clj/ignore-file` before the `(ns)` form.\n\n```clj\n#_:standard-clj/ignore-file\n\n(ns com.example.some-weird-file)\n\n;; ...\n```\n\nPlease note that `#_:standard-clj/ignore` will not work **inside** of the `ns` form, but it can be used\nto tell Standard Clojure Style to \"ignore the ns form entirely\":\n\n```clj\n;; this will NOT work\n\n(ns com.example.my-app\n  (:require\n    #_:standard-clj/ignore\n          [clojure.string         :as   string]))\n```\n\n```clj\n;; this WILL work\n\n#_:standard-clj/ignore\n(ns com.example.my-app\n  (:require\n          [clojure.string         :as   string]))\n```\n\nIt is recommended to use `#_:standard-clj/ignore` sparingly, and ideally not\nat all. However, there are always edge case exceptions where it makes sense\nto ignore formatting.\n\nI recommend ignoring whole forms at the top-level (ie: forms that start on\ncolumn 0, like `defn` or `ns`), instead of \"some formatted outside, some ignored inside\".\n\n```clj\n;; recommended, sparingly:\n\n#_:standard-clj/ignore\n(defn some-weird-fn []\n  ...)\n```\n\n```clj\n;; not recommended:\n\n(defn some-weird-fn []\n  (let [a \"a\"\n        b \"b\"]\n    #_:standard-clj/ignore ...))\n```\n\n## Creating a binary\n\n[Bun] has a neat feature where you can [create an executable binary] from JavaScript source:\n\n```sh\n## create a binary for Standard Clojure Style\nbun build ./cli.mjs --compile --outfile standard-clj\n\n## run your binary\n./standard-clj check /home/user1/my-project/src\n\n## move the binary to somewhere on your path\nmv standard-clj /usr/local/bin\n```\n\n[Bun]:https://bun.sh/\n[create an executable binary]:https://bun.sh/docs/bundler/executables\n\n## Formatting Rules\n\n\u003e NOTE: this is an incomplete list. I am working on a website that will document all of the formatting rules. 20 Sep 2024\n\n- trim trailing whitespace (ie: `rtrim` every line)\n- convert all `\"\\r\\n\"` to `\"\\n\"`\n- convert all tab characters to spaces (except tab characters inside of Strings)\n- ensure a single newline character (`\\n`) at the end of the file\n- [cljfmt option] `:remove-surrounding-whitespace?` = true\n- [cljfmt option] `:remove-trailing-whitespace?` = true\n- [cljfmt option] `:insert-missing-whitespace?` = true\n- [cljfmt option] `:remove-consecutive-blank-lines?` = true\n- format and sort `ns` forms according to Stuart Sierra's [how to ns]\n- indentation follows the guide from Niki Tonsky's [Better clojure formatting]\n  - with the addition of [Rule 3](https://github.com/clj-commons/formatter/issues/9#issuecomment-446167649) as proposed by Shaun Lebron\n- Use `#_ :standard-clj/ignore` or `#_ :standard-clj/ignore-file` to disable the formatter for certain special cases\n\n[how to ns]:https://stuartsierra.com/2016/clojure-how-to-ns.html\n[cljfmt option]:https://github.com/weavejester/cljfmt#formatting-options\n[Better clojure formatting]:https://tonsky.me/blog/clojurefmt/\n\n## Things that Standard Clojure Style does NOT do\n\n- no config options\n  - all projects using Standard Clojure Style follow the same rules\n- From cljfmt:\n  \u003e \"It is not the goal of the project to provide a one-to-one mapping between a Clojure syntax tree and formatted text; rather the intent is to correct formatting errors with minimal changes to the existing structure of the text.\n  \u003e If you want format completely unstructured Clojure code, the [zprint project](https://github.com/kkinnear/zprint) may be more suitable.\n- no enforced max line length\n  - text editors have the ability to wrap lines if you desire\n- vertical alignment of `let` forms and map literals are allowed\n  - the choice is up to the author\n  - [cljfmt option] `:remove-multiple-non-indenting-spaces?` = false\n  - I have seen too many code examples where vertical alignment adds clarity\n- no configuration or special rules for indentation\n  - the rules from [Better clojure formatting] are simple, easy to learn, and produce consistent-looking code\n  - 100% compatible with [Parinfer] users\n  - avoids the complexity of the [cljfmt `:indents` option]\n  - avoids the complexity of different rules for different forms (ie: no [semantic indentation])\n\n[Parinfer]:https://shaunlebron.github.io/parinfer/\n[cljfmt `:indents` option]:https://github.com/weavejester/cljfmt/blob/master/docs/INDENTS.md\n[semantic indentation]:https://guide.clojure.style/#body-indentation\n\n## References\n\n- https://clojureverse.org/t/clj-commons-building-a-formatter-like-gofmt-for-clojure/3240/95\n- https://github.com/clj-commons/formatter/issues/9\n- https://tonsky.me/blog/clojurefmt/\n- https://github.com/parinfer/parindent\n- [emoji length article](https://hsivonen.fi/string-length/)\n- https://github.com/weavejester/cljfmt/issues/36\n- https://github.com/weavejester/cljfmt/pull/251\n- https://github.com/weavejester/cljfmt/commit/23daaf0020526aaaaab1cd6363288e79091a97ba\n\n## Coding Style\n\nThe coding style for this library is intentionally very simple in order to make\nporting the algorithm to multiple languages easier. This is informed by my\nexperience porting [parinfer.js] to multiple languages ([parinfer-lua], [parinfer.py],\nand others).\n\nHere are some rules to follow:\n\n* each line should be one simple statement\n* do not use ternary operators\n* do not use variadic functions\n* no `for` loops, only use `while`\n* do not use `++` or `--` operators (wrap with function calls)\n* wrap all String and Array methods with function calls\n* do not early return from functions\n\nNote: this should not be considered a definitive list. I will add to this as I come across additional cases.\n\n[parinfer.js]:https://github.com/parinfer/parinfer.js\n[parinfer.py]:https://github.com/oakmac/parinfer.py\n[parinfer-lua]:https://github.com/oakmac/parinfer-lua\n\n## Development\n\nMake sure that either [Node.js] or [bun] are installed (both should work).\n\n```sh\n## run unit tests\nbun test\n\n## test a single file\nbun run jest format.test.js\n\n## lint JS\nbun run lint\n```\n\n[Node.js]:https://nodejs.org/\n[bun]:https://bun.sh/\n\n## Notes / Misc\n\n* ns order is:\n  1. `:refer-clojure`\n  1. `:require-macros`\n  1. `:require`\n  1. `:import`\n* Note that [how to ns] does not include guidance for `:require-macros`\n  * ClojureScript source ([1](https://github.com/clojure/clojurescript/blob/a53e163d9c495904389bd111665e93c4ff0c398e/src/main/cljs/cljs/pprint.cljs#L11), [2](https://github.com/clojure/clojurescript/blob/a53e163d9c495904389bd111665e93c4ff0c398e/src/main/cljs/cljs/repl.cljs#L10), [3](https://github.com/clojure/clojurescript/blob/a53e163d9c495904389bd111665e93c4ff0c398e/src/main/clojure/cljs/compiler.cljc#L12)) consistently places `:require-macros` above `:require`, so let's go with that\n* reader conditionals are placed at the bottom of the relevant ns section\n  * sorted alphabetically except for `:default` (if it exists), which is last\n\n[how to ns]:https://stuartsierra.com/2016/clojure-how-to-ns.html\n\n## License\n\n[ISC License](LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foakmac%2Fstandard-clojure-style-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foakmac%2Fstandard-clojure-style-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foakmac%2Fstandard-clojure-style-js/lists"}