datahike-browser-tests 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +405 -0
- package/.circleci/scripts/gen_ci.clj +194 -0
- package/.cirrus.yml +60 -0
- package/.clj-kondo/babashka/sci/config.edn +1 -0
- package/.clj-kondo/babashka/sci/sci/core.clj +9 -0
- package/.clj-kondo/config.edn +95 -0
- package/.dir-locals.el +2 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/1-bug-report.yml +68 -0
- package/.github/ISSUE_TEMPLATE/2-feature-request.yml +28 -0
- package/.github/ISSUE_TEMPLATE/config.yml +6 -0
- package/.github/pull_request_template.md +24 -0
- package/.github/workflows/native-image.yml +84 -0
- package/LICENSE +203 -0
- package/README.md +273 -0
- package/bb/deps.edn +9 -0
- package/bb/resources/github-fingerprints +3 -0
- package/bb/resources/native-image-tests/run-bb-pod-tests.clj +162 -0
- package/bb/resources/native-image-tests/run-libdatahike-tests +12 -0
- package/bb/resources/native-image-tests/run-native-image-tests +74 -0
- package/bb/resources/native-image-tests/run-python-tests +22 -0
- package/bb/resources/native-image-tests/testconfig.attr-refs.edn +6 -0
- package/bb/resources/native-image-tests/testconfig.edn +5 -0
- package/bb/resources/template/.settings/org.eclipse.jdt.apt.core.prefs +2 -0
- package/bb/resources/template/.settings/org.eclipse.jdt.core.prefs +9 -0
- package/bb/resources/template/.settings/org.eclipse.m2e.core.prefs +4 -0
- package/bb/resources/template/pom.xml +22 -0
- package/bb/src/tools/build.clj +132 -0
- package/bb/src/tools/clj_kondo.clj +32 -0
- package/bb/src/tools/deploy.clj +26 -0
- package/bb/src/tools/examples.clj +19 -0
- package/bb/src/tools/npm.clj +100 -0
- package/bb/src/tools/python.clj +14 -0
- package/bb/src/tools/release.clj +94 -0
- package/bb/src/tools/test.clj +148 -0
- package/bb/src/tools/version.clj +47 -0
- package/bb.edn +269 -0
- package/benchmark/src/benchmark/cli.clj +195 -0
- package/benchmark/src/benchmark/compare.clj +157 -0
- package/benchmark/src/benchmark/config.clj +316 -0
- package/benchmark/src/benchmark/measure.clj +187 -0
- package/benchmark/src/benchmark/store.clj +190 -0
- package/benchmark/test/benchmark/measure_test.clj +156 -0
- package/build.clj +30 -0
- package/config.edn +49 -0
- package/deps.edn +138 -0
- package/dev/sandbox.clj +82 -0
- package/dev/sandbox.cljs +127 -0
- package/dev/sandbox_benchmarks.clj +27 -0
- package/dev/sandbox_client.clj +87 -0
- package/dev/sandbox_transact_bench.clj +109 -0
- package/dev/user.clj +79 -0
- package/doc/README.md +96 -0
- package/doc/adl/README.md +6 -0
- package/doc/adl/adr-000-adr.org +28 -0
- package/doc/adl/adr-001-attribute-references.org +15 -0
- package/doc/adl/adr-002-build-tooling.org +54 -0
- package/doc/adl/adr-003-db-meta-data.md +52 -0
- package/doc/adl/adr-004-github-flow.md +40 -0
- package/doc/adl/adr-XYZ-template.md +30 -0
- package/doc/adl/index.org +3 -0
- package/doc/assets/datahike-logo.svg +3 -0
- package/doc/assets/datahiking-invoice.org +85 -0
- package/doc/assets/hhtree2.png +0 -0
- package/doc/assets/network_topology.svg +624 -0
- package/doc/assets/perf.png +0 -0
- package/doc/assets/schema_mindmap.mm +132 -0
- package/doc/assets/schema_mindmap.svg +970 -0
- package/doc/assets/temporal_index.mm +74 -0
- package/doc/backend-development.md +78 -0
- package/doc/bb-pod.md +89 -0
- package/doc/benchmarking.md +360 -0
- package/doc/bindings/edn-conversion.md +383 -0
- package/doc/cli.md +162 -0
- package/doc/cljdoc.edn +27 -0
- package/doc/cljs-support.md +133 -0
- package/doc/config.md +406 -0
- package/doc/contributing.md +114 -0
- package/doc/datalog-vs-sql.md +210 -0
- package/doc/datomic_differences.md +109 -0
- package/doc/development/pull-api-ns.md +186 -0
- package/doc/development/pull-frame-state-diagram.jpg +0 -0
- package/doc/distributed.md +566 -0
- package/doc/entity_spec.md +92 -0
- package/doc/gc.md +273 -0
- package/doc/java-api.md +808 -0
- package/doc/javascript-api.md +421 -0
- package/doc/libdatahike.md +86 -0
- package/doc/logging_and_error_handling.md +43 -0
- package/doc/norms.md +66 -0
- package/doc/schema-migration.md +85 -0
- package/doc/schema.md +287 -0
- package/doc/storage-backends.md +363 -0
- package/doc/store-id-refactoring.md +596 -0
- package/doc/time_variance.md +325 -0
- package/doc/unstructured.md +167 -0
- package/doc/versioning.md +261 -0
- package/examples/basic/README.md +19 -0
- package/examples/basic/deps.edn +6 -0
- package/examples/basic/docker-compose.yml +13 -0
- package/examples/basic/src/examples/core.clj +60 -0
- package/examples/basic/src/examples/schema.clj +155 -0
- package/examples/basic/src/examples/store.clj +60 -0
- package/examples/basic/src/examples/time_travel.clj +185 -0
- package/examples/java/.settings/org.eclipse.core.resources.prefs +3 -0
- package/examples/java/.settings/org.eclipse.jdt.apt.core.prefs +2 -0
- package/examples/java/.settings/org.eclipse.jdt.core.prefs +9 -0
- package/examples/java/.settings/org.eclipse.m2e.core.prefs +4 -0
- package/examples/java/README.md +162 -0
- package/examples/java/pom.xml +62 -0
- package/examples/java/src/main/java/examples/QuickStart.java +115 -0
- package/examples/java/src/main/java/examples/SchemaExample.java +148 -0
- package/examples/java/src/main/java/examples/TimeTravelExample.java +121 -0
- package/flake.lock +27 -0
- package/flake.nix +27 -0
- package/http-server/datahike/http/middleware.clj +75 -0
- package/http-server/datahike/http/server.clj +269 -0
- package/java/src/datahike/java/Database.java +274 -0
- package/java/src/datahike/java/Datahike.java +281 -0
- package/java/src/datahike/java/DatahikeGeneratedTest.java +349 -0
- package/java/src/datahike/java/DatahikeTest.java +370 -0
- package/java/src/datahike/java/EDN.java +170 -0
- package/java/src/datahike/java/IEntity.java +11 -0
- package/java/src/datahike/java/Keywords.java +161 -0
- package/java/src/datahike/java/SchemaFlexibility.java +52 -0
- package/java/src/datahike/java/Util.java +219 -0
- package/karma.conf.js +19 -0
- package/libdatahike/compile-cpp +7 -0
- package/libdatahike/src/datahike/impl/LibDatahikeBase.java +203 -0
- package/libdatahike/src/datahike/impl/libdatahike.clj +59 -0
- package/libdatahike/src/test_cpp.cpp +61 -0
- package/npm-package/PUBLISHING.md +140 -0
- package/npm-package/README.md +226 -0
- package/npm-package/package.template.json +34 -0
- package/npm-package/test-isomorphic.ts +281 -0
- package/npm-package/test.js +557 -0
- package/npm-package/typescript-test.ts +70 -0
- package/package.json +16 -0
- package/pydatahike/README.md +569 -0
- package/pydatahike/pyproject.toml +91 -0
- package/pydatahike/setup.py +42 -0
- package/pydatahike/src/datahike/__init__.py +134 -0
- package/pydatahike/src/datahike/_native.py +250 -0
- package/pydatahike/src/datahike/_version.py +2 -0
- package/pydatahike/src/datahike/database.py +722 -0
- package/pydatahike/src/datahike/edn.py +311 -0
- package/pydatahike/src/datahike/py.typed +0 -0
- package/pydatahike/tests/conftest.py +17 -0
- package/pydatahike/tests/test_basic.py +170 -0
- package/pydatahike/tests/test_database.py +51 -0
- package/pydatahike/tests/test_edn_conversion.py +299 -0
- package/pydatahike/tests/test_query.py +99 -0
- package/pydatahike/tests/test_schema.py +55 -0
- package/resources/clj-kondo.exports/io.replikativ/datahike/config.edn +5 -0
- package/resources/example_server.edn +4 -0
- package/shadow-cljs.edn +56 -0
- package/src/data_readers.clj +7 -0
- package/src/datahike/api/impl.cljc +176 -0
- package/src/datahike/api/specification.cljc +633 -0
- package/src/datahike/api/types.cljc +261 -0
- package/src/datahike/api.cljc +41 -0
- package/src/datahike/array.cljc +99 -0
- package/src/datahike/cli.clj +166 -0
- package/src/datahike/cljs.cljs +6 -0
- package/src/datahike/codegen/cli.clj +406 -0
- package/src/datahike/codegen/clj_kondo.clj +291 -0
- package/src/datahike/codegen/java.clj +403 -0
- package/src/datahike/codegen/naming.cljc +33 -0
- package/src/datahike/codegen/native.clj +559 -0
- package/src/datahike/codegen/pod.clj +488 -0
- package/src/datahike/codegen/python.clj +838 -0
- package/src/datahike/codegen/report.clj +55 -0
- package/src/datahike/codegen/typescript.clj +262 -0
- package/src/datahike/codegen/validation.clj +145 -0
- package/src/datahike/config.cljc +294 -0
- package/src/datahike/connections.cljc +16 -0
- package/src/datahike/connector.cljc +265 -0
- package/src/datahike/constants.cljc +142 -0
- package/src/datahike/core.cljc +297 -0
- package/src/datahike/datom.cljc +459 -0
- package/src/datahike/db/interface.cljc +119 -0
- package/src/datahike/db/search.cljc +305 -0
- package/src/datahike/db/transaction.cljc +937 -0
- package/src/datahike/db/utils.cljc +338 -0
- package/src/datahike/db.cljc +956 -0
- package/src/datahike/experimental/unstructured.cljc +126 -0
- package/src/datahike/experimental/versioning.cljc +172 -0
- package/src/datahike/externs.js +31 -0
- package/src/datahike/gc.cljc +69 -0
- package/src/datahike/http/client.clj +188 -0
- package/src/datahike/http/writer.clj +79 -0
- package/src/datahike/impl/entity.cljc +218 -0
- package/src/datahike/index/interface.cljc +93 -0
- package/src/datahike/index/persistent_set.cljc +469 -0
- package/src/datahike/index/utils.cljc +44 -0
- package/src/datahike/index.cljc +32 -0
- package/src/datahike/js/api.cljs +172 -0
- package/src/datahike/js/api_macros.clj +22 -0
- package/src/datahike/js.cljs +163 -0
- package/src/datahike/json.cljc +209 -0
- package/src/datahike/lru.cljc +146 -0
- package/src/datahike/migrate.clj +39 -0
- package/src/datahike/norm/norm.clj +245 -0
- package/src/datahike/online_gc.cljc +252 -0
- package/src/datahike/pod.clj +155 -0
- package/src/datahike/pull_api.cljc +325 -0
- package/src/datahike/query.cljc +1945 -0
- package/src/datahike/query_stats.cljc +88 -0
- package/src/datahike/readers.cljc +62 -0
- package/src/datahike/remote.cljc +218 -0
- package/src/datahike/schema.cljc +228 -0
- package/src/datahike/schema_cache.cljc +42 -0
- package/src/datahike/spec.cljc +101 -0
- package/src/datahike/store.cljc +80 -0
- package/src/datahike/tools.cljc +308 -0
- package/src/datahike/transit.cljc +80 -0
- package/src/datahike/writer.cljc +239 -0
- package/src/datahike/writing.cljc +362 -0
- package/src/deps.cljs +1 -0
- package/src-hitchhiker-tree/datahike/index/hitchhiker_tree/insert.cljc +76 -0
- package/src-hitchhiker-tree/datahike/index/hitchhiker_tree/upsert.cljc +128 -0
- package/src-hitchhiker-tree/datahike/index/hitchhiker_tree.cljc +213 -0
- package/test/datahike/backward_compatibility_test/src/backward_test.clj +37 -0
- package/test/datahike/integration_test/config_record_file_test.clj +14 -0
- package/test/datahike/integration_test/config_record_test.clj +14 -0
- package/test/datahike/integration_test/depr_config_uri_test.clj +15 -0
- package/test/datahike/integration_test/return_map_test.clj +62 -0
- package/test/datahike/integration_test.cljc +67 -0
- package/test/datahike/norm/norm_test.clj +124 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/003-tx-fn-test.edn +1 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/004-tx-data-and-tx-fn-test.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/01-transact-basic-characters.edn +2 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/02 add occupation.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/checksums.edn +12 -0
- package/test/datahike/norm/resources/simple-test/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/simple-test/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/simple-test/checksums.edn +4 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/003-tx-fn-test.edn +1 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/checksums.edn +6 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/second/004-tx-data-and-tx-fn-test.edn +5 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/second/checksums.edn +2 -0
- package/test/datahike/norm/resources/tx-fn-test/first/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/tx-fn-test/first/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/tx-fn-test/first/checksums.edn +4 -0
- package/test/datahike/norm/resources/tx-fn-test/second/003-tx-fn-test.edn +1 -0
- package/test/datahike/norm/resources/tx-fn-test/second/checksums.edn +2 -0
- package/test/datahike/test/api_test.cljc +895 -0
- package/test/datahike/test/array_test.cljc +40 -0
- package/test/datahike/test/attribute_refs/datoms_test.cljc +140 -0
- package/test/datahike/test/attribute_refs/db_test.cljc +42 -0
- package/test/datahike/test/attribute_refs/differences_test.cljc +515 -0
- package/test/datahike/test/attribute_refs/entity_test.cljc +89 -0
- package/test/datahike/test/attribute_refs/pull_api_test.cljc +320 -0
- package/test/datahike/test/attribute_refs/query_find_specs_test.cljc +59 -0
- package/test/datahike/test/attribute_refs/query_fns_test.cljc +130 -0
- package/test/datahike/test/attribute_refs/query_interop_test.cljc +47 -0
- package/test/datahike/test/attribute_refs/query_not_test.cljc +193 -0
- package/test/datahike/test/attribute_refs/query_or_test.cljc +137 -0
- package/test/datahike/test/attribute_refs/query_pull_test.cljc +156 -0
- package/test/datahike/test/attribute_refs/query_rules_test.cljc +176 -0
- package/test/datahike/test/attribute_refs/query_test.cljc +241 -0
- package/test/datahike/test/attribute_refs/temporal_search.cljc +22 -0
- package/test/datahike/test/attribute_refs/transact_test.cljc +220 -0
- package/test/datahike/test/attribute_refs/utils.cljc +128 -0
- package/test/datahike/test/cache_test.cljc +38 -0
- package/test/datahike/test/components_test.cljc +92 -0
- package/test/datahike/test/config_test.cljc +158 -0
- package/test/datahike/test/core_test.cljc +105 -0
- package/test/datahike/test/datom_test.cljc +44 -0
- package/test/datahike/test/db_test.cljc +54 -0
- package/test/datahike/test/entity_spec_test.cljc +159 -0
- package/test/datahike/test/entity_test.cljc +103 -0
- package/test/datahike/test/explode_test.cljc +143 -0
- package/test/datahike/test/filter_test.cljc +75 -0
- package/test/datahike/test/gc_test.cljc +159 -0
- package/test/datahike/test/http/server_test.clj +192 -0
- package/test/datahike/test/http/writer_test.clj +86 -0
- package/test/datahike/test/ident_test.cljc +32 -0
- package/test/datahike/test/index_test.cljc +345 -0
- package/test/datahike/test/insert.cljc +125 -0
- package/test/datahike/test/java_bindings_test.clj +6 -0
- package/test/datahike/test/listen_test.cljc +41 -0
- package/test/datahike/test/lookup_refs_test.cljc +266 -0
- package/test/datahike/test/lru_test.cljc +27 -0
- package/test/datahike/test/migrate_test.clj +297 -0
- package/test/datahike/test/model/core.cljc +376 -0
- package/test/datahike/test/model/invariant.cljc +142 -0
- package/test/datahike/test/model/rng.cljc +82 -0
- package/test/datahike/test/model_test.clj +217 -0
- package/test/datahike/test/nodejs_test.cljs +262 -0
- package/test/datahike/test/online_gc_test.cljc +475 -0
- package/test/datahike/test/pod_test.clj +369 -0
- package/test/datahike/test/pull_api_test.cljc +474 -0
- package/test/datahike/test/purge_test.cljc +144 -0
- package/test/datahike/test/query_aggregates_test.cljc +101 -0
- package/test/datahike/test/query_find_specs_test.cljc +52 -0
- package/test/datahike/test/query_fns_test.cljc +523 -0
- package/test/datahike/test/query_interop_test.cljc +47 -0
- package/test/datahike/test/query_not_test.cljc +189 -0
- package/test/datahike/test/query_or_test.cljc +158 -0
- package/test/datahike/test/query_pull_test.cljc +147 -0
- package/test/datahike/test/query_rules_test.cljc +248 -0
- package/test/datahike/test/query_stats_test.cljc +218 -0
- package/test/datahike/test/query_test.cljc +984 -0
- package/test/datahike/test/schema_test.cljc +424 -0
- package/test/datahike/test/specification_test.cljc +30 -0
- package/test/datahike/test/store_test.cljc +78 -0
- package/test/datahike/test/stress_test.cljc +57 -0
- package/test/datahike/test/time_variance_test.cljc +518 -0
- package/test/datahike/test/tools_test.clj +134 -0
- package/test/datahike/test/transact_test.cljc +518 -0
- package/test/datahike/test/tuples_test.cljc +564 -0
- package/test/datahike/test/unstructured_test.cljc +291 -0
- package/test/datahike/test/upsert_impl_test.cljc +205 -0
- package/test/datahike/test/upsert_test.cljc +363 -0
- package/test/datahike/test/utils.cljc +110 -0
- package/test/datahike/test/validation_test.cljc +48 -0
- package/test/datahike/test/versioning_test.cljc +56 -0
- package/test/datahike/test.cljc +66 -0
- package/tests.edn +24 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
(ns datahike.codegen.cli
|
|
2
|
+
"Generate CLI commands from API specification.
|
|
3
|
+
|
|
4
|
+
This namespace provides CLI-specific configuration and logic for:
|
|
5
|
+
- Deriving command names from operation categories
|
|
6
|
+
- Validating arguments with malli
|
|
7
|
+
- Generating hierarchical help text
|
|
8
|
+
- Handling stdin and file inputs"
|
|
9
|
+
(:require [clojure.string :as str]
|
|
10
|
+
[clojure.java.io :as io]
|
|
11
|
+
[clojure.edn :as edn]
|
|
12
|
+
[datahike.api.specification :refer [api-specification malli-schema->argslist]]
|
|
13
|
+
[datahike.api.types :as types]
|
|
14
|
+
[datahike.api :as d]
|
|
15
|
+
[datahike.json :as json]
|
|
16
|
+
[jsonista.core :as j]
|
|
17
|
+
[clj-cbor.core :as cbor]
|
|
18
|
+
[malli.core :as m]
|
|
19
|
+
[malli.error :as me])
|
|
20
|
+
(:import [java.util Date]))
|
|
21
|
+
|
|
22
|
+
;; =============================================================================
|
|
23
|
+
;; CLI-Specific Configuration
|
|
24
|
+
;; =============================================================================
|
|
25
|
+
|
|
26
|
+
(def cli-config
|
|
27
|
+
"CLI-specific configuration that extends the universal API specification.
|
|
28
|
+
|
|
29
|
+
Keys:
|
|
30
|
+
- :stdin? - Whether this operation accepts stdin input
|
|
31
|
+
- :stdin-arg - Which argument position (0-indexed) accepts stdin
|
|
32
|
+
- :file-arg - Which argument position supports --file option
|
|
33
|
+
- :batch-size - For streaming operations, how many items per batch"
|
|
34
|
+
|
|
35
|
+
{'transact {:stdin? true
|
|
36
|
+
:stdin-arg 1 ; tx-data argument
|
|
37
|
+
:file-arg 1
|
|
38
|
+
:batch-size 1000}
|
|
39
|
+
|
|
40
|
+
'load-entities {:stdin? true
|
|
41
|
+
:stdin-arg 1 ; entities argument
|
|
42
|
+
:batch-size 5000}})
|
|
43
|
+
|
|
44
|
+
(def cli-excluded-operations
|
|
45
|
+
"Operations excluded from CLI because they don't make sense in single-shot execution.
|
|
46
|
+
|
|
47
|
+
Reasons for exclusion:
|
|
48
|
+
- listen/unlisten: Require persistent connection with callbacks, CLI exits immediately
|
|
49
|
+
- release: Connection automatically released on CLI exit
|
|
50
|
+
- db (function): Redundant with db: prefix syntax
|
|
51
|
+
- tempid: Only useful within transactions, not standalone
|
|
52
|
+
- entity-db: Returns DB an entity came from, limited utility in CLI
|
|
53
|
+
- as-of/since/history/filter: Return DB objects that can't be serialized/deserialized,
|
|
54
|
+
use prefix syntax instead (e.g., asof:timestamp:config.edn)
|
|
55
|
+
- connect: Redundant with conn: prefix syntax
|
|
56
|
+
- db-with: Returns db value that can't be used in subsequent commands
|
|
57
|
+
- is-filtered: Requires filtered db input, which can't exist in CLI (filter excluded)"
|
|
58
|
+
#{'listen 'unlisten 'release 'db 'tempid 'entity-db
|
|
59
|
+
'as-of 'since 'history 'filter
|
|
60
|
+
'connect 'db-with 'is-filtered})
|
|
61
|
+
|
|
62
|
+
(defn cli-spec
|
|
63
|
+
"Get merged specification with CLI-specific config."
|
|
64
|
+
[op-name]
|
|
65
|
+
(merge (get api-specification op-name)
|
|
66
|
+
(get cli-config op-name)))
|
|
67
|
+
|
|
68
|
+
;; =============================================================================
|
|
69
|
+
;; Command Name Derivation
|
|
70
|
+
;; =============================================================================
|
|
71
|
+
|
|
72
|
+
(defn ->cli-command
|
|
73
|
+
"Derive CLI command from operation name - flat structure.
|
|
74
|
+
Returns a single-element vector with the command name.
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
'database-exists? => [\"database-exists\"]
|
|
78
|
+
'transact => [\"transact\"]
|
|
79
|
+
'q => [\"query\"]
|
|
80
|
+
'pull => [\"pull\"]"
|
|
81
|
+
[op-name categories]
|
|
82
|
+
(let [op-str (-> (name op-name)
|
|
83
|
+
(str/replace #"[?!]$" ""))] ; Remove ? and !
|
|
84
|
+
;; Special case: expand 'q to "query" for clarity
|
|
85
|
+
[(if (= op-str "q") "query" op-str)]))
|
|
86
|
+
|
|
87
|
+
(defn command->string
|
|
88
|
+
"Convert command vector to string: [\"query\"] => \"query\""
|
|
89
|
+
[cmd-vec]
|
|
90
|
+
(str/join " " cmd-vec))
|
|
91
|
+
|
|
92
|
+
(defn build-command-index
|
|
93
|
+
"Build a lookup map from command string to operation name.
|
|
94
|
+
|
|
95
|
+
Returns: {\"database-exists\" 'database-exists?, \"transact\" 'transact, ...}"
|
|
96
|
+
[]
|
|
97
|
+
(into {}
|
|
98
|
+
(for [[op-name {:keys [categories]}] api-specification
|
|
99
|
+
:when (not (contains? cli-excluded-operations op-name))
|
|
100
|
+
:let [cmd (->cli-command op-name categories)]]
|
|
101
|
+
[(command->string cmd) op-name])))
|
|
102
|
+
|
|
103
|
+
;; =============================================================================
|
|
104
|
+
;; Schema to Help Text
|
|
105
|
+
;; =============================================================================
|
|
106
|
+
|
|
107
|
+
(def type-descriptions
|
|
108
|
+
"Human-readable descriptions for common malli types."
|
|
109
|
+
{:datahike/SConfig "database configuration (map or file path)"
|
|
110
|
+
:datahike/SConnection "database connection"
|
|
111
|
+
:datahike/SDB "database value"
|
|
112
|
+
:datahike/SEId "entity identifier (number, keyword, or lookup ref)"
|
|
113
|
+
:datahike/STransactions "transaction data (vector of maps)"
|
|
114
|
+
:datahike/STransactionReport "transaction report map"
|
|
115
|
+
:datahike/SQueryArgs "query arguments map"
|
|
116
|
+
:datahike/SPullOptions "pull pattern options"
|
|
117
|
+
:datahike/SDatoms "sequence of datoms"
|
|
118
|
+
:datahike/SSchema "database schema map"
|
|
119
|
+
:datahike/SMetrics "database metrics map"
|
|
120
|
+
:string "string"
|
|
121
|
+
:int "integer"
|
|
122
|
+
:boolean "boolean"
|
|
123
|
+
:keyword "keyword"
|
|
124
|
+
:map "map"
|
|
125
|
+
:vector "vector"
|
|
126
|
+
:any "any value"})
|
|
127
|
+
|
|
128
|
+
(defn schema->help-text
|
|
129
|
+
"Convert a malli schema to human-readable help text.
|
|
130
|
+
|
|
131
|
+
Examples:
|
|
132
|
+
:datahike/SConfig => \"config\"
|
|
133
|
+
[:tuple :datahike/SConfig] => \"config\"
|
|
134
|
+
[:tuple :datahike/SConnection :datahike/STransactions] => \"connection, transactions\""
|
|
135
|
+
[schema]
|
|
136
|
+
(cond
|
|
137
|
+
;; Keyword reference - look up description
|
|
138
|
+
(keyword? schema)
|
|
139
|
+
(or (type-descriptions schema)
|
|
140
|
+
(name schema))
|
|
141
|
+
|
|
142
|
+
;; Tuple - list the args
|
|
143
|
+
(and (vector? schema) (= :tuple (first schema)))
|
|
144
|
+
(str/join ", " (map #(or (type-descriptions %) (str %)) (rest schema)))
|
|
145
|
+
|
|
146
|
+
;; :or - show alternatives
|
|
147
|
+
(and (vector? schema) (= :or (first schema)))
|
|
148
|
+
(str/join " or " (map schema->help-text (rest schema)))
|
|
149
|
+
|
|
150
|
+
;; :=> function schema - extract input
|
|
151
|
+
(and (vector? schema) (= :=> (first schema)))
|
|
152
|
+
(let [[_ input-schema _] schema]
|
|
153
|
+
(schema->help-text input-schema))
|
|
154
|
+
|
|
155
|
+
;; :cat - sequential args
|
|
156
|
+
(and (vector? schema) (= :cat (first schema)))
|
|
157
|
+
(str/join ", " (map schema->help-text (rest schema)))
|
|
158
|
+
|
|
159
|
+
;; :function multi-arity - show first arity
|
|
160
|
+
(and (vector? schema) (= :function (first schema)))
|
|
161
|
+
(schema->help-text (second schema))
|
|
162
|
+
|
|
163
|
+
;; [:sequential :any] or similar
|
|
164
|
+
(and (vector? schema) (= :sequential (first schema)))
|
|
165
|
+
"sequence"
|
|
166
|
+
|
|
167
|
+
;; Default
|
|
168
|
+
:else (str schema)))
|
|
169
|
+
|
|
170
|
+
(defn args-help
|
|
171
|
+
"Generate argument help text for an operation."
|
|
172
|
+
[args-schema]
|
|
173
|
+
(schema->help-text args-schema))
|
|
174
|
+
|
|
175
|
+
;; =============================================================================
|
|
176
|
+
;; Help Text Generation
|
|
177
|
+
;; =============================================================================
|
|
178
|
+
|
|
179
|
+
(defn first-sentence
|
|
180
|
+
"Extract first sentence from docstring."
|
|
181
|
+
[doc]
|
|
182
|
+
(-> doc
|
|
183
|
+
(str/split #"\.\s")
|
|
184
|
+
first
|
|
185
|
+
(str ".")))
|
|
186
|
+
|
|
187
|
+
(defn group-by-category
|
|
188
|
+
"Group operations by their primary category.
|
|
189
|
+
Returns: {category-keyword [op-names...]}"
|
|
190
|
+
[]
|
|
191
|
+
(reduce
|
|
192
|
+
(fn [acc [op-name {:keys [categories]}]]
|
|
193
|
+
(if (contains? cli-excluded-operations op-name)
|
|
194
|
+
acc
|
|
195
|
+
(let [primary-cat (first categories)]
|
|
196
|
+
(update acc primary-cat (fnil conj []) op-name))))
|
|
197
|
+
{}
|
|
198
|
+
api-specification))
|
|
199
|
+
|
|
200
|
+
(def category-titles
|
|
201
|
+
"Human-readable titles for categories."
|
|
202
|
+
{:database "Database Operations"
|
|
203
|
+
:connection "Connection Operations"
|
|
204
|
+
:transaction "Transaction Operations"
|
|
205
|
+
:query "Query Operations"
|
|
206
|
+
:pull "Pull Operations"
|
|
207
|
+
:index "Index Operations"
|
|
208
|
+
:lifecycle "Lifecycle Operations"
|
|
209
|
+
:schema "Schema Operations"
|
|
210
|
+
:advanced "Advanced Operations"
|
|
211
|
+
:write "Write Operations"
|
|
212
|
+
:read "Read Operations"
|
|
213
|
+
:diagnostics "Diagnostics"
|
|
214
|
+
:maintenance "Maintenance"})
|
|
215
|
+
|
|
216
|
+
(def category-order
|
|
217
|
+
"Order for displaying categories in help."
|
|
218
|
+
[:database :connection :transaction :query :pull :schema :diagnostics :maintenance])
|
|
219
|
+
|
|
220
|
+
(defn generate-help
|
|
221
|
+
"Generate hierarchical help text from API specification."
|
|
222
|
+
[options-summary]
|
|
223
|
+
(let [grouped (group-by-category)
|
|
224
|
+
banner "▁▃▅▄▇▅▃▅▃▁ \033[1mdata\033[0mhike cli"
|
|
225
|
+
version (or (try (some-> (clojure.java.io/resource "DATAHIKE_VERSION")
|
|
226
|
+
slurp
|
|
227
|
+
str/trim)
|
|
228
|
+
(catch Exception _ nil))
|
|
229
|
+
"development")]
|
|
230
|
+
(str/join
|
|
231
|
+
"\n"
|
|
232
|
+
(concat
|
|
233
|
+
[banner
|
|
234
|
+
(str "version " version)
|
|
235
|
+
""
|
|
236
|
+
"This is the Datahike command line interface."
|
|
237
|
+
""
|
|
238
|
+
"The commands reflect the datahike.api Clojure API."
|
|
239
|
+
"Use db:config_file for database values, conn:config_file for connections."
|
|
240
|
+
""
|
|
241
|
+
"Usage: dthk [options] <command> [arguments]"
|
|
242
|
+
""
|
|
243
|
+
"Options:"
|
|
244
|
+
options-summary
|
|
245
|
+
""
|
|
246
|
+
"Commands:"
|
|
247
|
+
""]
|
|
248
|
+
|
|
249
|
+
;; Generate hierarchical command listing
|
|
250
|
+
(mapcat
|
|
251
|
+
(fn [category]
|
|
252
|
+
(concat
|
|
253
|
+
[(str " " (get category-titles category category) ":")]
|
|
254
|
+
(for [op-name (get grouped category)
|
|
255
|
+
:let [{:keys [args doc]} (cli-spec op-name)
|
|
256
|
+
cmd (->cli-command op-name (list category))
|
|
257
|
+
cmd-str (command->string cmd)
|
|
258
|
+
args-str (args-help args)]]
|
|
259
|
+
(format " %-25s %s"
|
|
260
|
+
(str cmd-str " " args-str)
|
|
261
|
+
(first-sentence doc)))
|
|
262
|
+
[""]))
|
|
263
|
+
(filter #(contains? grouped %) category-order))
|
|
264
|
+
|
|
265
|
+
["Remote Databases:"
|
|
266
|
+
" Use :writer or :remote-peer in your config file to connect via HTTP."
|
|
267
|
+
" Example config with :writer for distributed writes:"
|
|
268
|
+
" {:store {:backend :file :path \"/shared/db\"}"
|
|
269
|
+
" :writer {:backend :datahike-server :url \"http://localhost:4444\" :token \"xyz\"}}"
|
|
270
|
+
" See doc/distributed.md for details."
|
|
271
|
+
""
|
|
272
|
+
"For more information on a specific command, use: dthk help <command>"]))))
|
|
273
|
+
|
|
274
|
+
;; =============================================================================
|
|
275
|
+
;; Argument Parsing and Validation
|
|
276
|
+
;; =============================================================================
|
|
277
|
+
|
|
278
|
+
(def input-parsers
|
|
279
|
+
"Map of regex patterns to parser functions for handling prefixed inputs.
|
|
280
|
+
|
|
281
|
+
Patterns:
|
|
282
|
+
- conn:file.edn => Connect and return connection
|
|
283
|
+
- db:file.edn => Connect and return database value
|
|
284
|
+
- history:file.edn => Return history database
|
|
285
|
+
- since:timestamp:file.edn => Return database since timestamp
|
|
286
|
+
- asof:timestamp:file.edn => Return database as-of timestamp
|
|
287
|
+
- edn:file.edn => Read EDN from file
|
|
288
|
+
- json:file.edn => Read JSON from file
|
|
289
|
+
- cbor:file.cbor => Read CBOR from file"
|
|
290
|
+
{#"conn:(.+)" #(d/connect (edn/read-string (slurp %)))
|
|
291
|
+
#"db:(.+)" #(deref (d/connect (edn/read-string (slurp %))))
|
|
292
|
+
#"history:(.+)" #(d/history @(d/connect (edn/read-string (slurp %))))
|
|
293
|
+
#"since:(.+):(.+)" #(d/since @(d/connect (edn/read-string (slurp %2)))
|
|
294
|
+
(Date. ^Long (edn/read-string %1)))
|
|
295
|
+
#"asof:(.+):(.+)" #(d/as-of @(d/connect (edn/read-string (slurp %2)))
|
|
296
|
+
(Date. ^Long (edn/read-string %1)))
|
|
297
|
+
#"cbor:(.+)" #(cbor/decode (io/input-stream %))
|
|
298
|
+
#"edn:(.+)" (comp edn/read-string slurp)
|
|
299
|
+
#"json:(.+)" (comp #(j/read-value % json/mapper) slurp)})
|
|
300
|
+
|
|
301
|
+
(defn parse-prefix
|
|
302
|
+
"Parse input prefixes like conn:file.edn, db:file.edn, etc.
|
|
303
|
+
Returns the parsed value or tries to read as EDN if no prefix matches.
|
|
304
|
+
|
|
305
|
+
Examples:
|
|
306
|
+
\"conn:config.edn\" => (d/connect config)
|
|
307
|
+
\"db:config.edn\" => @(d/connect config)
|
|
308
|
+
\"{:x 1}\" => {:x 1}"
|
|
309
|
+
[s]
|
|
310
|
+
(if-not (string? s)
|
|
311
|
+
s ; Already parsed, return as-is
|
|
312
|
+
(if-let [res (reduce (fn [_ [pattern parser-fn]]
|
|
313
|
+
(let [match (re-matches pattern s)]
|
|
314
|
+
(when (first match)
|
|
315
|
+
(reduced (apply parser-fn (rest match))))))
|
|
316
|
+
nil
|
|
317
|
+
input-parsers)]
|
|
318
|
+
res
|
|
319
|
+
;; No prefix matched - try to parse as EDN
|
|
320
|
+
(try
|
|
321
|
+
(edn/read-string s)
|
|
322
|
+
(catch Exception _
|
|
323
|
+
;; If EDN parsing fails, return as string
|
|
324
|
+
s)))))
|
|
325
|
+
|
|
326
|
+
(defn validate-args
|
|
327
|
+
"Validate arguments against malli schema.
|
|
328
|
+
Returns {:ok parsed-args} or {:error explanation}"
|
|
329
|
+
[schema args]
|
|
330
|
+
(let [validated (m/validate schema args {:registry types/registry})]
|
|
331
|
+
(if validated
|
|
332
|
+
{:ok args}
|
|
333
|
+
{:error (me/humanize
|
|
334
|
+
(m/explain schema args {:registry types/registry}))})))
|
|
335
|
+
|
|
336
|
+
(defn try-arities
|
|
337
|
+
"Try multiple arities in order until one validates.
|
|
338
|
+
For multi-arity functions, returns {:ok args arity-index} or {:error last-error}"
|
|
339
|
+
[function-schema args]
|
|
340
|
+
(if (and (vector? function-schema) (= :function (first function-schema)))
|
|
341
|
+
;; Multi-arity: try each arity schema
|
|
342
|
+
(let [arity-schemas (rest function-schema)]
|
|
343
|
+
(loop [schemas arity-schemas
|
|
344
|
+
idx 0]
|
|
345
|
+
(if (empty? schemas)
|
|
346
|
+
{:error "No arity matched the provided arguments"}
|
|
347
|
+
(let [arity-schema (first schemas)
|
|
348
|
+
[_ input-schema _] arity-schema
|
|
349
|
+
result (validate-args input-schema args)]
|
|
350
|
+
(if (:ok result)
|
|
351
|
+
(assoc result :arity idx)
|
|
352
|
+
(recur (rest schemas) (inc idx)))))))
|
|
353
|
+
;; Single arity
|
|
354
|
+
(validate-args function-schema args)))
|
|
355
|
+
|
|
356
|
+
(defn format-validation-error
|
|
357
|
+
"Format malli validation error for CLI users."
|
|
358
|
+
[op-name schema args error]
|
|
359
|
+
(let [{:keys [doc examples]} (cli-spec op-name)
|
|
360
|
+
example (first examples)]
|
|
361
|
+
(str "❌ Invalid arguments for '" op-name "':\n\n"
|
|
362
|
+
" Expected: " (args-help schema) "\n"
|
|
363
|
+
" Got: " (pr-str args) "\n\n"
|
|
364
|
+
" Error: " (pr-str error) "\n"
|
|
365
|
+
(when example
|
|
366
|
+
(str "\n Example: " (:code example) "\n")))))
|
|
367
|
+
|
|
368
|
+
;; =============================================================================
|
|
369
|
+
;; Command Dispatch
|
|
370
|
+
;; =============================================================================
|
|
371
|
+
|
|
372
|
+
(defn dispatch-command
|
|
373
|
+
"Parse and dispatch a CLI command.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
cmd-parts - Command parts from CLI, e.g. [\"db\" \"exists\"]
|
|
377
|
+
raw-args - Raw argument strings from CLI
|
|
378
|
+
cli-opts - Parsed CLI options (format, verbosity, etc.)
|
|
379
|
+
|
|
380
|
+
Returns the result of calling the operation, or exits on error."
|
|
381
|
+
[cmd-parts raw-args cli-opts]
|
|
382
|
+
(let [cmd-str (str/join " " cmd-parts)
|
|
383
|
+
command-index (build-command-index)
|
|
384
|
+
op-name (get command-index cmd-str)]
|
|
385
|
+
|
|
386
|
+
(if-not op-name
|
|
387
|
+
(do
|
|
388
|
+
(println "❌ Unknown command:" cmd-str)
|
|
389
|
+
(println "\nUse 'dthk --help' to see available commands.")
|
|
390
|
+
(System/exit 1))
|
|
391
|
+
|
|
392
|
+
(let [{:keys [args impl]} (cli-spec op-name)
|
|
393
|
+
;; Parse arguments (handle prefixes, files, etc.)
|
|
394
|
+
parsed-args (mapv parse-prefix raw-args)
|
|
395
|
+
;; Validate with malli
|
|
396
|
+
validation (try-arities args parsed-args)]
|
|
397
|
+
|
|
398
|
+
(if (:ok validation)
|
|
399
|
+
;; Success - call implementation
|
|
400
|
+
;; impl is a symbol, need to resolve it to a var
|
|
401
|
+
(apply (resolve impl) parsed-args)
|
|
402
|
+
|
|
403
|
+
;; Validation failed - show error
|
|
404
|
+
(do
|
|
405
|
+
(println (format-validation-error op-name args parsed-args (:error validation)))
|
|
406
|
+
(System/exit 1)))))))
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
(ns datahike.codegen.clj-kondo
|
|
2
|
+
"Generate clj-kondo export config from api.specification.
|
|
3
|
+
|
|
4
|
+
This namespace provides tooling to generate clj-kondo configuration that:
|
|
5
|
+
- Exports all dynamically generated API functions
|
|
6
|
+
- Provides proper arglists for each function
|
|
7
|
+
- Includes documentation strings
|
|
8
|
+
- Provides type information for :type-mismatch linter
|
|
9
|
+
- Enables IDE autocomplete, signature hints, and type checking
|
|
10
|
+
|
|
11
|
+
The generated config allows clj-kondo to understand the dynamically
|
|
12
|
+
expanded API functions from the emit-api macro, eliminating yellow
|
|
13
|
+
squiggles and providing full IDE support."
|
|
14
|
+
(:require [datahike.api.specification :refer [api-specification malli-schema->argslist]]
|
|
15
|
+
[clojure.java.io :as io]
|
|
16
|
+
[clojure.pprint :as pprint]))
|
|
17
|
+
|
|
18
|
+
;; =============================================================================
|
|
19
|
+
;; Malli Schema to clj-kondo Type Conversion
|
|
20
|
+
;; =============================================================================
|
|
21
|
+
|
|
22
|
+
(defn- malli->clj-kondo-type
|
|
23
|
+
"Convert a Malli type to a clj-kondo type keyword.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
:int -> :int
|
|
27
|
+
:string -> :string
|
|
28
|
+
:boolean -> :boolean
|
|
29
|
+
:datahike/SDB -> :any (custom types become :any)
|
|
30
|
+
[:vector :int] -> :vector
|
|
31
|
+
[:map ...] -> :map"
|
|
32
|
+
[schema]
|
|
33
|
+
(cond
|
|
34
|
+
;; Primitive types that clj-kondo understands natively
|
|
35
|
+
(#{:int :integer :double :string :boolean :keyword :symbol :nil :any} schema)
|
|
36
|
+
schema
|
|
37
|
+
|
|
38
|
+
;; Collection types
|
|
39
|
+
(and (vector? schema) (= :vector (first schema)))
|
|
40
|
+
:vector
|
|
41
|
+
|
|
42
|
+
(and (vector? schema) (= :sequential (first schema)))
|
|
43
|
+
:seqable
|
|
44
|
+
|
|
45
|
+
(and (vector? schema) (= :map (first schema)))
|
|
46
|
+
:map
|
|
47
|
+
|
|
48
|
+
(and (vector? schema) (= :set (first schema)))
|
|
49
|
+
:set
|
|
50
|
+
|
|
51
|
+
;; Function schemas - treat as :ifn
|
|
52
|
+
(and (vector? schema) (#{:=> :function} (first schema)))
|
|
53
|
+
:ifn
|
|
54
|
+
|
|
55
|
+
;; Or/alt schemas - use :any for now (could be smarter)
|
|
56
|
+
(and (vector? schema) (#{:or :alt} (first schema)))
|
|
57
|
+
:any
|
|
58
|
+
|
|
59
|
+
;; Maybe/optional - extract inner type
|
|
60
|
+
(and (vector? schema) (= :maybe (first schema)))
|
|
61
|
+
(if-let [inner (second schema)]
|
|
62
|
+
(malli->clj-kondo-type inner)
|
|
63
|
+
:any)
|
|
64
|
+
|
|
65
|
+
;; Custom types (namespaced keywords like :datahike/SDB) -> :any
|
|
66
|
+
(keyword? schema)
|
|
67
|
+
:any
|
|
68
|
+
|
|
69
|
+
;; Symbols (type references) -> :any
|
|
70
|
+
(symbol? schema)
|
|
71
|
+
:any
|
|
72
|
+
|
|
73
|
+
;; Fn predicates [:fn pred] -> :any
|
|
74
|
+
(and (vector? schema) (= :fn (first schema)))
|
|
75
|
+
:any
|
|
76
|
+
|
|
77
|
+
;; Default
|
|
78
|
+
:else
|
|
79
|
+
:any))
|
|
80
|
+
|
|
81
|
+
(defn- extract-arity-info
|
|
82
|
+
"Extract arity information from a Malli function schema.
|
|
83
|
+
|
|
84
|
+
Input: [:=> [:cat Type1 Type2] RetType]
|
|
85
|
+
Output: {:args [:type1 :type2] :ret :rettype}
|
|
86
|
+
|
|
87
|
+
Input: [:function [:=> [:cat Type1] RetType] [:=> [:cat Type1 Type2] RetType]]
|
|
88
|
+
Output: [{:args [:type1] :ret :rettype}
|
|
89
|
+
{:args [:type1 :type2] :ret :rettype}]"
|
|
90
|
+
[schema]
|
|
91
|
+
(cond
|
|
92
|
+
;; Single arity: [:=> [:cat Type1 Type2] RetType]
|
|
93
|
+
(and (vector? schema) (= :=> (first schema)))
|
|
94
|
+
(let [[_ input-schema ret-schema] schema]
|
|
95
|
+
(if (and (vector? input-schema) (= :cat (first input-schema)))
|
|
96
|
+
[{:args (mapv malli->clj-kondo-type (rest input-schema))
|
|
97
|
+
:ret (malli->clj-kondo-type ret-schema)}]
|
|
98
|
+
;; No :cat - assume no args
|
|
99
|
+
[{:args []
|
|
100
|
+
:ret (malli->clj-kondo-type ret-schema)}]))
|
|
101
|
+
|
|
102
|
+
;; Multi-arity: [:function [:=> ...] [:=> ...]]
|
|
103
|
+
(and (vector? schema) (= :function (first schema)))
|
|
104
|
+
(vec (for [arity-schema (rest schema)]
|
|
105
|
+
(when (and (vector? arity-schema) (= :=> (first arity-schema)))
|
|
106
|
+
(let [[_ input-schema ret-schema] arity-schema]
|
|
107
|
+
(if (and (vector? input-schema) (= :cat (first input-schema)))
|
|
108
|
+
{:args (mapv malli->clj-kondo-type (rest input-schema))
|
|
109
|
+
:ret (malli->clj-kondo-type ret-schema)}
|
|
110
|
+
;; No :cat - assume no args
|
|
111
|
+
{:args []
|
|
112
|
+
:ret (malli->clj-kondo-type ret-schema)})))))
|
|
113
|
+
|
|
114
|
+
;; Fallback
|
|
115
|
+
:else
|
|
116
|
+
nil))
|
|
117
|
+
|
|
118
|
+
(defn- generate-type-definition
|
|
119
|
+
"Generate clj-kondo type definition for a single API function.
|
|
120
|
+
|
|
121
|
+
Returns a map with :arities for :type-mismatch linter."
|
|
122
|
+
[fn-name {:keys [args]}]
|
|
123
|
+
(when-let [arities (extract-arity-info args)]
|
|
124
|
+
(let [;; Convert arities to clj-kondo format: {arity {:args [...] :ret ...}}
|
|
125
|
+
arities-map (into {}
|
|
126
|
+
(map-indexed
|
|
127
|
+
(fn [idx {:keys [args ret]}]
|
|
128
|
+
[(count args) {:args args :ret ret}])
|
|
129
|
+
arities))]
|
|
130
|
+
{:arities arities-map})))
|
|
131
|
+
|
|
132
|
+
;; =============================================================================
|
|
133
|
+
;; Config Generation
|
|
134
|
+
;; =============================================================================
|
|
135
|
+
|
|
136
|
+
(defn- generate-var-definition
|
|
137
|
+
"Generate clj-kondo var definition for a single API function.
|
|
138
|
+
|
|
139
|
+
Returns a map with :arglists and :doc for the function."
|
|
140
|
+
[fn-name {:keys [args doc]}]
|
|
141
|
+
(let [arglists (malli-schema->argslist args)
|
|
142
|
+
;; Ensure arglists is a proper list (not lazy seq or vector)
|
|
143
|
+
arglists-list (if (list? arglists)
|
|
144
|
+
arglists
|
|
145
|
+
(apply list arglists))]
|
|
146
|
+
;; Use a quoted form (via syntax-quote) so it prints as '(...) not (quote (...))
|
|
147
|
+
{:arglists `'~arglists-list
|
|
148
|
+
:doc doc}))
|
|
149
|
+
|
|
150
|
+
(defn generate-config
|
|
151
|
+
"Generate complete clj-kondo export configuration.
|
|
152
|
+
|
|
153
|
+
Returns an EDN map with:
|
|
154
|
+
- :var-definitions - Basic function signatures for IDE support
|
|
155
|
+
- :linters :type-mismatch - Type information for type checking"
|
|
156
|
+
[]
|
|
157
|
+
(let [var-defs (into {}
|
|
158
|
+
(map (fn [[fn-name spec]]
|
|
159
|
+
[fn-name (generate-var-definition fn-name spec)])
|
|
160
|
+
api-specification))
|
|
161
|
+
type-defs (into {}
|
|
162
|
+
(keep (fn [[fn-name spec]]
|
|
163
|
+
(when-let [type-def (generate-type-definition fn-name spec)]
|
|
164
|
+
[fn-name type-def]))
|
|
165
|
+
api-specification))]
|
|
166
|
+
{:var-definitions
|
|
167
|
+
{'datahike.api var-defs}
|
|
168
|
+
|
|
169
|
+
:linters
|
|
170
|
+
{:type-mismatch
|
|
171
|
+
{:namespaces
|
|
172
|
+
{'datahike.api type-defs}}}}))
|
|
173
|
+
|
|
174
|
+
(defn write-config!
|
|
175
|
+
"Write clj-kondo export configuration to file.
|
|
176
|
+
|
|
177
|
+
This should be the resources/ location so it gets packaged in the jar
|
|
178
|
+
and auto-imported by consuming projects.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
output-path - Path to write config.edn (usually resources/clj-kondo.exports/io.replikativ/datahike/config.edn)"
|
|
182
|
+
[output-path]
|
|
183
|
+
(let [config (generate-config)
|
|
184
|
+
output-file (io/file output-path)]
|
|
185
|
+
|
|
186
|
+
;; Ensure parent directories exist
|
|
187
|
+
(.mkdirs (.getParentFile output-file))
|
|
188
|
+
|
|
189
|
+
;; Write export config (using prn for now to avoid pprint issues with quoted forms)
|
|
190
|
+
(with-open [writer (io/writer output-file)]
|
|
191
|
+
(binding [*out* writer]
|
|
192
|
+
(println ";; clj-kondo export configuration for Datahike")
|
|
193
|
+
(println ";; AUTO-GENERATED from api-specification")
|
|
194
|
+
(println ";; To regenerate: bb codegen-clj-kondo")
|
|
195
|
+
(println)
|
|
196
|
+
(prn config)))
|
|
197
|
+
|
|
198
|
+
(let [var-count (count (get-in config [:var-definitions 'datahike.api]))
|
|
199
|
+
type-count (count (get-in config [:linters :type-mismatch :namespaces 'datahike.api]))]
|
|
200
|
+
(println (str "Generated clj-kondo export config: " output-path))
|
|
201
|
+
(println (str " Exported " var-count " API functions with signatures"))
|
|
202
|
+
(println (str " Generated " type-count " type definitions for type checking"))
|
|
203
|
+
output-path)))
|
|
204
|
+
|
|
205
|
+
(defn copy-export-to-local!
|
|
206
|
+
"Copy export config to .clj-kondo directory for local development.
|
|
207
|
+
|
|
208
|
+
The export config in resources/ gets packaged in the jar. For local
|
|
209
|
+
development, we also need it in .clj-kondo/datahike/datahike/ which
|
|
210
|
+
is referenced via :config-paths.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
export-path - Source path (resources/clj-kondo.exports/io.replikativ/datahike/config.edn)
|
|
214
|
+
local-path - Destination path (.clj-kondo/datahike/datahike/config.edn)"
|
|
215
|
+
[export-path local-path]
|
|
216
|
+
(let [export-file (io/file export-path)
|
|
217
|
+
local-file (io/file local-path)]
|
|
218
|
+
|
|
219
|
+
;; Ensure parent directories exist
|
|
220
|
+
(.mkdirs (.getParentFile local-file))
|
|
221
|
+
|
|
222
|
+
;; Copy file
|
|
223
|
+
(io/copy export-file local-file)
|
|
224
|
+
|
|
225
|
+
(println (str "Copied to local config: " local-path))
|
|
226
|
+
local-path))
|
|
227
|
+
|
|
228
|
+
(defn update-main-config!
|
|
229
|
+
"Update main .clj-kondo/config.edn with type-mismatch linter.
|
|
230
|
+
|
|
231
|
+
Reads existing config, merges in type definitions, and writes back.
|
|
232
|
+
This enables type checking for Datahike's own project (export config
|
|
233
|
+
is for consuming libraries).
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
main-config-path - Path to main config (usually .clj-kondo/config.edn)"
|
|
237
|
+
[main-config-path]
|
|
238
|
+
(let [config (generate-config)
|
|
239
|
+
type-defs (get-in config [:linters :type-mismatch :namespaces 'datahike.api])
|
|
240
|
+
main-config-file (io/file main-config-path)
|
|
241
|
+
existing-config (when (.exists main-config-file)
|
|
242
|
+
(read-string (slurp main-config-file)))
|
|
243
|
+
|
|
244
|
+
;; Merge type-mismatch into existing linters
|
|
245
|
+
updated-config (update-in existing-config
|
|
246
|
+
[:linters :type-mismatch :namespaces]
|
|
247
|
+
(fn [existing]
|
|
248
|
+
(merge existing {'datahike.api type-defs})))]
|
|
249
|
+
|
|
250
|
+
;; Write updated config with pretty printing
|
|
251
|
+
(with-open [writer (io/writer main-config-file)]
|
|
252
|
+
(binding [*out* writer]
|
|
253
|
+
(println ";; clj-kondo configuration for Datahike")
|
|
254
|
+
(println ";; Type definitions for datahike.api are AUTO-GENERATED")
|
|
255
|
+
(println ";; To regenerate: bb codegen-clj-kondo")
|
|
256
|
+
(println)
|
|
257
|
+
(pprint/pprint updated-config)))
|
|
258
|
+
|
|
259
|
+
(println (str "Updated main config: " main-config-path))
|
|
260
|
+
(println (str " Added type checking for " (count type-defs) " API functions"))
|
|
261
|
+
main-config-path))
|
|
262
|
+
|
|
263
|
+
;; =============================================================================
|
|
264
|
+
;; Verification
|
|
265
|
+
;; =============================================================================
|
|
266
|
+
|
|
267
|
+
(defn verify-config
|
|
268
|
+
"Verify that generated config is up-to-date.
|
|
269
|
+
|
|
270
|
+
Reads existing config and compares to what would be generated.
|
|
271
|
+
Returns true if up-to-date, false otherwise.
|
|
272
|
+
|
|
273
|
+
Useful for CI checks to ensure codegen was run."
|
|
274
|
+
[config-path]
|
|
275
|
+
(try
|
|
276
|
+
(let [expected (generate-config)
|
|
277
|
+
actual (read-string (slurp config-path))]
|
|
278
|
+
(= expected actual))
|
|
279
|
+
(catch Exception e
|
|
280
|
+
(println (str "Error verifying config: " (.getMessage e)))
|
|
281
|
+
false)))
|
|
282
|
+
|
|
283
|
+
(comment
|
|
284
|
+
;; Generate config
|
|
285
|
+
(write-config! ".clj-kondo/datahike/datahike/config.edn")
|
|
286
|
+
|
|
287
|
+
;; Verify config is up-to-date
|
|
288
|
+
(verify-config ".clj-kondo/datahike/datahike/config.edn")
|
|
289
|
+
|
|
290
|
+
;; Preview what would be generated
|
|
291
|
+
(clojure.pprint/pprint (generate-config)))
|