Skip to content

Commit 406b292

Browse files
committed
Implement pure CLJC Sqids and harden verification tooling
This replaces the prior sqids-java/sqids-javascript integration with a native Clojure/ClojureScript implementation while keeping the public API stable. The algorithm now lives in focused CLJC namespaces for alphabet, block-list, encoding, decoding, initialization, results, and platform helpers, with the bundled blocklist moved to resources and refreshed by a Babashka updater. Internally, encode/decode now flow through a total result-based core so validation and error handling are explicit and testable across platforms. Only `org.sqids.clojure/{sqids,encode,decode}` throw. Cross-namespace encode/decode fdefs live in `org.sqids.clojure.invariants`, which allows a stronger encode-side round-trip property without creating implementation cycles. Generator-heavy spec support also moved into mirrored `org.sqids.clojure.generators/*` namespaces to keep runtime files readable. Tooling and CI were modernized around Kaocha as the single test entrypoint, 100% coverage enforcement, machine-readable coverage outputs, JUnit artifacts, and a parity harness plus CI job against `sqids-spec`. The repo now uses local wrappers for clj-kondo and cljstyle, stricter lint policy, markdownlint and prettier hooks, and refreshed AGENTS/README guidance for the current workflow.
1 parent eba1561 commit 406b292

Some content is hidden

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

54 files changed

+3999
-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)