Skip to content

Commit 8344854

Browse files
committed
Port Sqids to pure CLJC and harden quality tooling
This replaces the prior sqids-java/sqids-javascript integration with a native Clojure/ClojureScript implementation while keeping the public API stable. The algorithm path is now shared in CLJC, supports large integer domains, and improves readability with clearer naming, structure, and inline docs. Internally, encode/decode now run through a total result-oriented core so validation and error behavior are explicit and testable across platforms. Throwing is constrained to the public edge functions affected by API contracts. Platform-specific behavior was pushed into platform namespaces to reduce reader-conditionals and duplicated logic. Tooling was modernized for a model public Clojure library: local wrappers for clj-kondo and cljstyle, stricter lint policy, markdownlint + prettier hooks, Babashka-based blocklist generation, and a simplified test entrypoint via Kaocha. Testing and CI were expanded with always-on coverage enforcement, machine-readable coverage outputs, JUnit XML reporting, and artifact uploads. Specs and generators were strengthened to exercise canonical/erroneous decode paths more directly and improve failure quality. Documentation and contributor guidance were updated throughout, including repository standards in AGENTS.md and clearer maintenance/release workflows.
1 parent eba1561 commit 8344854

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+3806
-539
lines changed

.clj-kondo/config.edn

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{:linters
2+
{:aliased-namespace-symbol {:level :error}
3+
:aliased-namespace-var-usage {:level :error}
4+
:aliased-referred-var {:level :error}
5+
:case-quoted-test {:level :error}
6+
:case-symbol-test {:level :error}
7+
:clj-kondo-config {:level :error}
8+
:cond-else {:level :error}
9+
:condition-always-true {:level :error}
10+
:consistent-alias {:level :error
11+
:aliases {clojure.edn edn
12+
clojure.set set
13+
clojure.spec.alpha s
14+
clojure.spec.gen.alpha gen
15+
clojure.string str
16+
clojure.test t}}
17+
:def-fn {:level :error}
18+
:deprecated-namespace {:level :error}
19+
:deprecated-var {:level :error}
20+
:destructured-or-always-evaluates {:level :error}
21+
:destructured-or-binding-of-same-map {:level :error}
22+
:discouraged-java-method {:level :error}
23+
:discouraged-namespace {:level :error}
24+
:discouraged-tag {:level :error}
25+
:discouraged-var {:level :error}
26+
:do-template {:level :error}
27+
:docstring-leading-trailing-whitespace {:level :error}
28+
:docstring-no-summary {:level :error}
29+
:duplicate-key-args {:level :error}
30+
:duplicate-refer {:level :error}
31+
:earmuffed-var-not-dynamic {:level :error}
32+
:equals-expected-position {:level :error
33+
:position :first}
34+
:equals-false {:level :error}
35+
:equals-float {:level :error}
36+
:equals-nil {:level :error}
37+
:equals-true {:level :error}
38+
:if-nil-return {:level :error}
39+
:inline-def {:level :error}
40+
:is-message-not-string {:level :error}
41+
:keyword-binding {:level :error}
42+
:line-length {:level :error
43+
:max-line-length 120}
44+
:locking-suspicious-lock {:level :error}
45+
:loop-without-recur {:level :error}
46+
:main-without-gen-class {:level :error}
47+
:min-clj-kondo-version {:level :error}
48+
:minus-one {:level :error}
49+
:missing-body-in-when {:level :error}
50+
:missing-clause-in-try {:level :error}
51+
:missing-docstring {:level :error}
52+
:missing-else-branch {:level :error}
53+
:missing-protocol-method {:level :error}
54+
:missing-test-assertion {:level :error}
55+
:multiple-async-in-deftest {:level :error}
56+
:non-arg-vec-return-type-hint {:level :error}
57+
:not-empty? {:level :error}
58+
:plus-one {:level :error}
59+
:reduce-without-init {:level :error}
60+
:redundant-call {:level :error}
61+
:redundant-do {:level :error}
62+
:redundant-expression {:level :error}
63+
:redundant-fn-wrapper {:level :error}
64+
:redundant-format {:level :error}
65+
:redundant-ignore {:level :error}
66+
:redundant-let {:level :error}
67+
:redundant-let-binding {:level :error}
68+
:redundant-nested-call {:level :error}
69+
:redundant-primitive-coercion {:level :error}
70+
:redundant-str-call {:level :error}
71+
:refer {:level :error}
72+
:refer-all {:level :error}
73+
:redefined-var {:level :error}
74+
:schema-misplaced-return {:level :error}
75+
:self-requiring-namespace {:level :error}
76+
:shadowed-fn-param {:level :error}
77+
:shadowed-var {:level :error}
78+
:single-key-in {:level :error}
79+
:single-logical-operand {:level :error}
80+
:single-operand-comparison {:level :error}
81+
:underscore-in-namespace {:level :error}
82+
:unbound-destructuring-default {:level :error}
83+
:uninitialized-var {:level :error}
84+
:unreachable-code {:level :error}
85+
:unresolved-excluded-var {:level :error}
86+
:unresolved-namespace {:level :error}
87+
:unresolved-protocol-method {:level :error}
88+
:unresolved-var {:level :error}
89+
:unquote-not-syntax-quoted {:level :error}
90+
:unsorted-imports {:level :error}
91+
:unsorted-required-namespaces {:level :error
92+
:sort :case-insensitive}
93+
:unused-alias {:level :error}
94+
:unused-binding {:level :error
95+
:exclude-destructured-keys-in-fn-args false
96+
:exclude-destructured-as false
97+
:exclude-defmulti-args false}
98+
:unused-excluded-var {:level :error}
99+
:unused-import {:level :error}
100+
:unused-namespace {:level :error
101+
:simple-libspec false}
102+
:unused-private-var {:level :error}
103+
:unused-referred-var {:level :error}
104+
:unused-value {:level :error}
105+
:use {:level :error}
106+
:used-underscored-binding {:level :error}
107+
:var-same-name-except-case {:level :error}
108+
:warn-on-reflection {:level :error
109+
:warn-only-on-interop true}}}

.github/workflows/clojure.yml

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
name: Set up Java
2424
with:
2525
distribution: temurin
26-
java-version: 11
26+
java-version: 21
2727
- uses: actions/setup-python@v4
2828
name: Set up Python
2929
with:
@@ -34,10 +34,6 @@ jobs:
3434
with:
3535
path: ~/.cache/pre-commit
3636
key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
37-
- name: Docker cache
38-
uses: ScribeMD/docker-cache@0.3.6
39-
with:
40-
key: ${{ runner.os }}-docker-${{ hashFiles('.pre-commit-config.yaml') }}
4137
- uses: actions/cache@v3
4238
name: Clojure cache
4339
with:
@@ -47,19 +43,79 @@ jobs:
4743
~/.clojure
4844
~/.cpcache
4945
key: ${{ runner.os }}-clojure-${{ hashFiles('deps.edn') }}
50-
- name: Install Clojure
51-
run: |
52-
curl -L -O https://github.com/clojure/brew-install/releases/latest/download/posix-install.sh
53-
chmod +x posix-install.sh
54-
sudo ./posix-install.sh
55-
rm posix-install.sh
46+
- name: Install Clojure tools
47+
uses: DeLaGuardo/setup-clojure@13
48+
with:
49+
cli: latest
50+
bb: latest
51+
clj-kondo: 2026.01.19
52+
cljstyle: 0.15.0
5653
- name: Run pre-commit hooks
5754
run: |
5855
pip install -r requirements.txt
59-
pre-commit run --all-files
60-
- name: Run clj tests
61-
run: bin/test clj
62-
- name: Run cljs tests
56+
SKIP=kaocha-test pre-commit run --all-files
57+
- name: Run tests
6358
run: |
6459
npm install
65-
bin/test cljs
60+
bin/kaocha
61+
- name: Upload coverage artifact
62+
if: always()
63+
uses: actions/upload-artifact@v4
64+
with:
65+
name: coverage-report
66+
path: target/coverage
67+
if-no-files-found: warn
68+
- name: Upload JUnit XML artifact
69+
if: always()
70+
uses: actions/upload-artifact@v4
71+
with:
72+
name: junit-xml
73+
path: target/test-results/junit.xml
74+
if-no-files-found: warn
75+
76+
spec-parity:
77+
runs-on: ubuntu-latest
78+
79+
env:
80+
SQIDS_SPEC_DIR: ${{ github.workspace }}/target/sqids-spec
81+
82+
steps:
83+
- uses: actions/checkout@v3
84+
name: Check out repository
85+
- uses: actions/checkout@v3
86+
name: Check out sqids-spec
87+
with:
88+
repository: sqids/sqids-spec
89+
ref: main
90+
path: target/sqids-spec
91+
- uses: actions/setup-node@v4
92+
name: Set up Node
93+
with:
94+
node-version: lts/*
95+
cache: npm
96+
cache-dependency-path: |
97+
package-lock.json
98+
target/sqids-spec/package-lock.json
99+
- uses: actions/setup-java@v4
100+
name: Set up Java
101+
with:
102+
distribution: temurin
103+
java-version: 21
104+
- uses: actions/cache@v3
105+
name: Clojure cache
106+
with:
107+
path: |
108+
~/.m2/repository
109+
~/.gitlibs
110+
~/.clojure
111+
~/.cpcache
112+
key: ${{ runner.os }}-clojure-${{ hashFiles('deps.edn') }}
113+
- name: Install Clojure tools
114+
uses: DeLaGuardo/setup-clojure@13
115+
with:
116+
cli: latest
117+
- name: Install sqids-spec dependencies
118+
working-directory: target/sqids-spec
119+
run: npm ci
120+
- name: Run sqids-spec parity
121+
run: bin/parity

.gitignore

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
*.class *.iml
1+
*.class
2+
*.iml
23
*.jar
34
*.log
45
*.swp
@@ -7,13 +8,19 @@
78
.calva/output-window/
89
.classpath
910
.clj-kondo/.cache
11+
.cljs_node_repl/
1012
.cpcache
13+
.cpcache/
1114
.eastwood
1215
.factorypath
1316
.hg/
1417
.hgignore
1518
.idea
1619
.lein-*
20+
.lein-deps-sum
21+
.lein-failures
22+
.lein-plugins/
23+
.lein-repl-history
1724
.lsp/.cache
1825
.lsp/sqlite.db
1926
.nrepl-*
@@ -28,9 +35,14 @@
2835
.sw*
2936
.vscode
3037
/checkouts
38+
/checkouts/
3139
/classes
40+
/classes/
41+
/lib/
42+
/out
3243
/src/gen
3344
/target
45+
/target/
3446
Brewfile.lock.json
3547
cljs-test-runner-out/
3648
node_modules/

.markdownlint-cli2.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
config:
3+
MD013: false
4+
ignores:
5+
- node_modules/**

.pre-commit-config.yaml

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,52 @@
11
repos:
2-
- repo: https://github.com/clj-kondo/clj-kondo
3-
rev: v2023.10.20
4-
hooks:
5-
- id: clj-kondo-docker
6-
pass_filenames: false
7-
require_serial: true
82
- repo: https://github.com/pre-commit/pre-commit-hooks
9-
rev: v4.5.0
3+
rev: v6.0.0
104
hooks:
115
- id: check-shebang-scripts-are-executable
126
- id: trailing-whitespace
137
- id: end-of-file-fixer
148
- id: check-added-large-files
159
- repo: https://github.com/scop/pre-commit-shfmt
16-
rev: v3.7.0-4
10+
rev: v3.12.0-2
1711
hooks:
18-
- id: shfmt-docker
19-
entry: mvdan/shfmt:v3.7.0
12+
- id: shfmt
2013
args: [-w, -s, -i, "2"]
2114
- repo: https://github.com/koalaman/shellcheck-precommit
22-
rev: v0.9.0
15+
rev: v0.11.0
2316
hooks:
2417
- id: shellcheck
2518
- repo: local
2619
hooks:
20+
- id: clj-kondo
21+
name: clj-kondo
22+
entry: bin/_clj-kondo --lint src test bin/update-blocklist build.clj deps.edn tests.edn shadow-cljs.edn
23+
language: system
24+
pass_filenames: false
25+
require_serial: true
2726
- id: cljstyle
2827
name: cljstyle
2928
entry: bin/_cljstyle fix
3029
language: system
3130
types: [file]
31+
- id: kaocha-test
32+
name: kaocha-test
33+
entry: bin/kaocha
34+
language: system
35+
pass_filenames: false
36+
always_run: true
37+
require_serial: true
38+
- id: markdownlint-cli2
39+
name: markdownlint-cli2
40+
language: node
41+
entry: markdownlint-cli2
42+
additional_dependencies: ["markdownlint-cli2@0.21.0"]
43+
types: [markdown]
44+
args: ["--config", ".markdownlint-cli2.yaml", "--fix"]
3245
- id: prettier
3346
name: prettier
34-
language: docker_image
35-
entry: tmknom/prettier
47+
language: node
48+
entry: prettier
49+
additional_dependencies: ["prettier@3.8.1"]
3650
types: [text]
3751
args: [--write, --list-different, --ignore-unknown]
3852
- id: git-diff

0 commit comments

Comments
 (0)