├── .github └── workflows │ └── test.yaml ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY.md ├── VERSION_PREFIX ├── bench └── transit │ └── bench.cljs ├── bin ├── build_jar └── roundtrip ├── build ├── doc ├── package ├── package_local ├── release └── revision ├── deps.edn ├── pom.xml ├── project.clj ├── resources ├── index.html ├── index_dev.html ├── integer.html ├── node_externs.js └── test.edn ├── script ├── build.clj └── repl.clj ├── src └── cognitect │ └── transit.cljs └── test └── transit ├── roundtrip └── core.cljs ├── test └── core.cljs └── test_runner.cljs /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push] 3 | 4 | jobs: 5 | # Runtime Tests 6 | runtime-test: 7 | name: Runtime Tests 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - uses: DeLaGuardo/setup-clojure@3.1 13 | with: 14 | tools-deps: '1.10.1.763' 15 | 16 | - name: Build tests 17 | run: clojure -M:test 18 | 19 | - name: Run tests 20 | run: | 21 | node target/transit_test.js | tee test-out.txt 22 | grep -qxF '0 failures, 0 errors.' test-out.txt 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | *jar 4 | /lib/ 5 | /classes/ 6 | /out/ 7 | /doc/ 8 | /target/ 9 | .lein-deps-sum 10 | .lein-repl-history 11 | .lein-plugins/ 12 | .cljs_node_repl 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # transit-cljs 2 | 3 | Transit is a data format and a set of libraries for conveying values between 4 | applications written in different languages. This library provides support for 5 | marshalling Transit data to/from ClojureScript. Unlike the Java and Clojure 6 | implementations it relies on the non-streaming JSON parsing mechanism of the 7 | host JavaScript environment. 8 | 9 | * [Rationale](https://blog.cognitect.com/blog/2014/7/22/transit) 10 | * [API docs](https://cognitect.github.io/transit-cljs/) 11 | * [Specification](https://github.com/cognitect/transit-format) 12 | * [Getting Started](https://github.com/cognitect/transit-cljs/wiki/Getting-Started) 13 | 14 | This implementation's major.minor version number corresponds to the version of 15 | the Transit specification it supports. 16 | 17 | _NOTE: Transit is intended primarily as a wire protocol for transferring data between applications. If storing Transit data durably, readers and writers are expected to use the same version of Transit and you are responsible for migrating/transforming/re-storing that data when and if the transit format changes._ 18 | 19 | ## Releases and Dependency Information 20 | 21 | * Latest release: 0.8.280 22 | * [All Released Versions](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.cognitect%22%20AND%20a%3A%22transit-cljs%22) 23 | 24 | ### Leiningen 25 | 26 | Add the following to your `project.clj` `:dependencies`: 27 | 28 | ``` 29 | [com.cognitect/transit-cljs "0.8.280"] 30 | ``` 31 | 32 | ### Maven 33 | 34 | [Maven](https://maven.apache.org/) dependency information: 35 | 36 | ```xml 37 | 38 | com.cognitect 39 | transit-cljs 40 | 0.8.280 41 | 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```clojure 47 | (ns example 48 | (:require [cognitect.transit :as t])) 49 | 50 | (defn roundtrip [x] 51 | (let [w (t/writer :json) 52 | r (t/reader :json)] 53 | (t/read r (t/write w x)))) 54 | 55 | (defn test-roundtrip [] 56 | (let [list1 [:red :green :blue] 57 | list2 [:apple :pear :grape] 58 | data {(t/integer 1) list1 59 | (t/integer 2) list2} 60 | data' (roundtrip data)] 61 | (assert (= data data')))) 62 | ``` 63 | 64 | ## Default Type Mapping 65 | 66 | Abbreviations: 67 | * cc = cljs.core 68 | * gm = goog.math 69 | * cct = com.cognitect.transit 70 | 71 | |Transit type|Write accepts|Read returns| 72 | |------------|-------------|------------| 73 | |null|null|null| 74 | |string|String|String| 75 | |boolean|Boolean|Boolean| 76 | |integer|Number, gm.Long|Number, gm.Long| 77 | |decimal|Number|Number| 78 | |keyword|cc.Keyword|cc.Keyword| 79 | |symbol|cc.Symbol|cc.Symbol| 80 | |big integer|cct.TaggedValue|cct.TaggedValue| 81 | |big decimal|cct.TaggedValue|cct.TaggedValue| 82 | |time|Date|Date| 83 | |uri|cct.URI|cct.URI| 84 | |uuid|cct.UUID|cct.UUID| 85 | |char|String|String| 86 | |array|cc.IVector|cc.IVector| 87 | |list|cc.IList|cc.IList| 88 | |set|cc.ISet|cc.ISet| 89 | |map|cc.IMap|cc.IMap| 90 | |link|cct.Link|cct.Link| 91 | |cmap|cct.IMap|cct.IMap| 92 | 93 | ## Contributing 94 | 95 | This library is open source, developed internally by Cognitect. We welcome 96 | discussions of potential problems and enhancement suggestions on the 97 | [transit-format mailing 98 | list](https://groups.google.com/forum/#!forum/transit-format). Issues can be 99 | filed using GitHub [issues](https://github.com/cognitect/transit-cljs/issues) 100 | for this project. Because transit is incorporated into products and client 101 | projects, we prefer to do development internally and are not accepting pull 102 | requests or patches. 103 | 104 | ## Development 105 | 106 | ### Dependencies 107 | 108 | Install dependencies with 109 | 110 | ``` 111 | lein deps 112 | ``` 113 | 114 | ### Running the tests & benchmarks 115 | 116 | Running the tests: 117 | 118 | ``` 119 | lein cljsbuild once test 120 | ``` 121 | 122 | In order to run the [transit-format](https://github.com/cognitect/transit-format) 123 | `bin/verify` you must first clone transit-format into the same parent directory 124 | as your transit-cljs checkout and build the roundtrip file: 125 | 126 | ``` 127 | lein cljsbuild once roundtrip 128 | ``` 129 | 130 | To run the benchmarks you must first clone 131 | [transit-format](https://github.com/cognitect/transit-format) into the same 132 | parent directory as your transit-cljs checkout. 133 | 134 | Running the benchmarks: 135 | 136 | ``` 137 | lein cljsbuild once bench 138 | node target/transit.bench.js 139 | ``` 140 | 141 | ### Build 142 | 143 | #### Build JAR for ClojureScript 144 | 145 | Assuming you have a 146 | JDK and [Maven](https://maven.apache.org) installed, the following will 147 | install a JAR suitable for use from ClojureScript into your local 148 | Maven repository. 149 | 150 | ``` 151 | build/package_local 152 | ``` 153 | 154 | ## Copyright and License 155 | 156 | Copyright © 2014-2022 Cognitect 157 | 158 | Licensed under the Apache License, Version 2.0 (the "License"); 159 | you may not use this file except in compliance with the License. 160 | You may obtain a copy of the License at 161 | 162 | https://www.apache.org/licenses/LICENSE-2.0 163 | 164 | Unless required by applicable law or agreed to in writing, software 165 | distributed under the License is distributed on an "AS IS" BASIS, 166 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 167 | See the License for the specific language governing permissions and 168 | limitations under the License. 169 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy for Nubank Open Source Projects 2 | 3 | ## Supported Versions 4 | 5 | Nubank supports the latest version of each of our open-source projects. Once a new version is released, we stop providing patches for security issues in older versions. 6 | 7 | ## Reporting Security Issues 8 | 9 | Your efforts to responsibly disclose your findings are sincerely appreciated and will be taken into account to acknowledge your contributions. 10 | If you discover a vulnerability, please do the following: 11 | 12 | 1. E-mail your findings to [security@nubank.com.br](mailto:security@nubank.com.br). If the issue is sensitive, please use [our PGP key](https://nubank.com.br/.well-known/security.txt) to encrypt your communications with us. 13 | 2. Do not take advantage of the vulnerability or problem you have discovered. 14 | 3. Do not reveal the problem to others until it has been resolved. 15 | 4. Provide sufficient information to reproduce the problem so we can resolve it as quickly as possible. 16 | 5. You will receive a response from us acknowledging receipt of your vulnerability report. 17 | 6. You'll receive regular updates about our progress. 18 | 7. Once the issue is resolved, we would like to mention your name in any dispatches about the issue so that we can credit you for your discovery. Please engage in responsible privacy practices when disclosing bugs to us, and we'll handle each report with utmost urgency. 19 | 20 | ## Preferred Languages 21 | 22 | We prefer all communications to be in English. 23 | 24 | ## Policy Adherence 25 | 26 | We greatly value your assistance in discovering and reporting vulnerabilities, and look forward to working with users who wish to help ensure Nubank's open-source projects' safety and security. Thank you for supporting Nubank's mission and helping ensure the highest levels of security for our community! 27 | -------------------------------------------------------------------------------- /VERSION_PREFIX: -------------------------------------------------------------------------------- 1 | 0.8 -------------------------------------------------------------------------------- /bench/transit/bench.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright 2014 Cognitect. All Rights Reserved. 2 | ;; 3 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ;; you may not use this file except in compliance with the License. 5 | ;; You may obtain a copy of the License at 6 | ;; 7 | ;; http://www.apache.org/licenses/LICENSE-2.0 8 | ;; 9 | ;; Unless required by applicable law or agreed to in writing, software 10 | ;; distributed under the License is distributed on an "AS-IS" BASIS, 11 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ;; See the License for the specific language governing permissions and 13 | ;; limitations under the License. 14 | 15 | (ns transit.test 16 | (:require [cognitect.transit :as t] 17 | [cljs.reader :as r])) 18 | 19 | (enable-console-print!) 20 | 21 | (def fs (js/require "fs")) 22 | (def rjson (. fs (readFileSync "../transit-format/examples/0.8/example.verbose.json" "utf8"))) 23 | (def json (. fs (readFileSync "../transit-format/examples/0.8/example.json" "utf8"))) 24 | (def r (t/reader :json)) 25 | (def w (t/writer :json)) 26 | (def w-nc (t/writer :json {:cache false})) 27 | 28 | (println "100 iters, JSON.parse seattle data") 29 | (time 30 | (dotimes [_ 100] 31 | (.parse js/JSON rjson))) 32 | 33 | (println "100 iters, transit read seattle data") 34 | (time 35 | (dotimes [_ 100] 36 | (.read r json))) 37 | 38 | (println "100 iters, JSON.stringify seattle data") 39 | (let [seattle (.parse js/JSON rjson)] 40 | (time 41 | (dotimes [_ 100] 42 | (.stringify js/JSON seattle)))) 43 | 44 | (println "100 iters, transit write seattle data") 45 | (let [seattle (.read r json)] 46 | (time 47 | (dotimes [_ 100] 48 | (.write w seattle)))) 49 | 50 | (println "100 iters, transit write seattle data no-cache") 51 | (let [seattle (.read r json)] 52 | (time 53 | (dotimes [_ 100] 54 | (.write w-nc seattle)))) 55 | 56 | (println "100 iters, pr-str seattle data") 57 | (let [seattle (pr-str (.read r json))] 58 | (time 59 | (dotimes [_ 100] 60 | (r/read-string seattle)))) 61 | 62 | (println "100 iters, pr-str seattle data") 63 | (let [seattle (.read r json)] 64 | (time 65 | (dotimes [_ 100] 66 | (pr-str seattle)))) 67 | 68 | 69 | -------------------------------------------------------------------------------- /bin/build_jar: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | cd src 6 | 7 | jar cf transit-cljs.jar cognitect 8 | 9 | mkdir -p ../target 10 | 11 | mv transit-cljs.jar ../target/ 12 | -------------------------------------------------------------------------------- /bin/roundtrip: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | cd `dirname $0`/.. 6 | 7 | node target/roundtrip.js "$@" 8 | -------------------------------------------------------------------------------- /build/doc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo -e "Building docs\n" 6 | rm -rf doc 7 | lein codox 8 | echo -e "Built docs at doc/\n" 9 | 10 | echo -e "Checking out gh-pages branch\n" 11 | rm -rf gh-pages 12 | git clone --quiet --branch=gh-pages git@github.com:cognitect/transit-cljs.git gh-pages > /dev/null 13 | cd gh-pages 14 | 15 | echo -e "Replacing old gh-pages content with new docs\n" 16 | git rm -rf ./* 17 | cp -Rf ../doc/* ./ 18 | git add -f . 19 | git commit -m "Updating gh-pages with new api docs" 20 | git push -fq origin gh-pages > /dev/null 21 | cd .. 22 | 23 | echo -e "Cleaning up\n" 24 | rm -rf gh-pages 25 | 26 | -------------------------------------------------------------------------------- /build/package: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "Cleaning..." 6 | rm -rf ./target 7 | 8 | echo "Calculating version..." 9 | prefix=`cat VERSION_PREFIX` 10 | suffix=`build/revision` 11 | version=$prefix.$suffix 12 | echo $version 13 | 14 | echo "Packaging..." 15 | bin/build_jar 16 | mvn versions:set -DnewVersion=${version} 17 | mvn install:install-file -Dfile=./target/transit-cljs.jar -DpomFile=pom.xml -DcreateChecksum=true -DlocalRepositoryPath=./target/package 18 | mvn versions:revert 19 | 20 | echo "Package done!" 21 | -------------------------------------------------------------------------------- /build/package_local: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "Cleaning..." 6 | rm -rf ./target 7 | 8 | echo "Calculating version..." 9 | prefix=`cat VERSION_PREFIX` 10 | suffix=`build/revision` 11 | version=$prefix.$suffix 12 | echo $version 13 | 14 | echo "Packaging..." 15 | bin/build_jar 16 | mvn versions:set -DnewVersion=${version} 17 | mvn install:install-file -Dfile=./target/transit-cljs.jar -DpomFile=pom.xml 18 | mvn versions:revert 19 | 20 | echo "Package done!" 21 | -------------------------------------------------------------------------------- /build/release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "Cleaning..." 6 | rm -rf ./target 7 | 8 | echo "Calculating version..." 9 | prefix=`cat VERSION_PREFIX` 10 | suffix=`build/revision` 11 | version=$prefix.$suffix 12 | echo $version 13 | 14 | target_name=transit-cljs-${version} 15 | 16 | echo "Releasing..." 17 | mvn versions:set -DnewVersion=${version} 18 | mvn clean deploy 19 | mvn versions:revert 20 | 21 | echo "Tagging..." 22 | git tag -a v${version} -m "Release ${version}" 23 | git push origin v${version} 24 | 25 | echo "Updating README.md versions" 26 | sed -i '' "s/[[:digit:]]\{1,2\}\.[[:digit:]]\{1,2\}\.[[:digit:]]\{2,4\}/${version}/g" README.md 27 | git commit -v -m "Update README.md with ${version}" README.md 28 | git push 29 | 30 | echo "Updating gh-pages with new api docs" 31 | build/doc 32 | 33 | echo "Release done!" 34 | -------------------------------------------------------------------------------- /build/revision: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Returns the revision number used for deployment. 4 | 5 | set -e 6 | 7 | REVISION=`git --no-replace-objects describe --tags --match v0.0` 8 | 9 | # Extract the version number from the string. Do this in two steps so 10 | # it is a little easier to understand. 11 | REVISION=${REVISION:5} # drop the first 5 characters 12 | REVISION=${REVISION:0:${#REVISION}-9} # drop the last 9 characters 13 | 14 | echo $REVISION 15 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:deps {org.clojure/clojurescript {:mvn/version "1.10.238"} 2 | com.cognitect/transit-js {:mvn/version "0.8.874"}} 3 | :aliases {:repl {:extra-paths ["test"] 4 | :main-opts ["-m" "cljs.main" "-re" "node" "-r"]} 5 | :test {:extra-paths ["test"] 6 | :main-opts ["-m" "cljs.main" "-co" "resources/test.edn" "-c"]}}} 7 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.cognitect 7 | transit-cljs 8 | jar 9 | dev 10 | transit-cljs 11 | transit-cljs bindings for ClojureScript 12 | https://github.com/cognitect/transit-cljs 13 | 14 | 15 | The Apache Software License, Version 2.0 16 | https://www.apache.org/licenses/LICENSE-2.0.txt 17 | repo 18 | 19 | 20 | 21 | scm:git:git://github.com/cognitect/transit-cljs.git 22 | 23 | 24 | scm:git:ssh://git@github.com/cognitect/transit-cljs.git 25 | 26 | f34f4d4b62ba3b11a3d8e4905a4f2c17e68f29dc 27 | 28 | https://github.com/cognitect/transit-cljs 29 | 30 | 31 | src 32 | test 33 | 34 | 35 | src 36 | 37 | 38 | 39 | 40 | dev-resources 41 | 42 | 43 | resources 44 | 45 | 46 | target 47 | target/classes 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-javadoc-plugin 52 | 2.9.1 53 | 54 | 55 | attach-javadocs 56 | 57 | jar 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-source-plugin 67 | 2.2.1 68 | 69 | 70 | attach-sources 71 | 72 | jar-no-fork 73 | 74 | 75 | 76 | 77 | 78 | org.sonatype.plugins 79 | nexus-staging-maven-plugin 80 | 1.6.2 81 | true 82 | 83 | ossrh 84 | https://oss.sonatype.org/ 85 | true 86 | 87 | 88 | 89 | org.apache.maven.plugins 90 | maven-gpg-plugin 91 | 1.5 92 | 93 | 94 | sign-artifacts 95 | verify 96 | 97 | sign 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | central 107 | https://repo1.maven.org/maven2/ 108 | 109 | false 110 | 111 | 112 | true 113 | 114 | 115 | 116 | clojars 117 | https://clojars.org/repo/ 118 | 119 | true 120 | 121 | 122 | true 123 | 124 | 125 | 126 | 127 | 128 | org.clojure 129 | clojurescript 130 | 1.10.238 131 | provided 132 | 133 | 134 | com.cognitect 135 | transit-js 136 | 0.8.874 137 | 138 | 139 | 140 | 141 | David Nolen 142 | david.nolen@cognitect.com 143 | Cognitect 144 | https://cognitect.com 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject com.cognitect/transit-cljs "0.8.264" 2 | :description "transit bindings for ClojureScript" 3 | :url "http://github.com/cognitect/transit-cljs" 4 | 5 | :dependencies [[org.clojure/clojure "1.8.0" :scope "provided"] 6 | [org.clojure/clojurescript "1.10.238" :scope "provided"] 7 | [com.cognitect/transit-js "0.8.874"]] 8 | 9 | :plugins [[lein-cljsbuild "1.1.7"] 10 | [lein-codox "0.10.7"]] 11 | 12 | :scm {:connection "scm:git:git@github.com:cognitect/transit-cljs.git" 13 | :developerConnection "scm:git:git@github.com:cognitect/transit-cljs.git" 14 | :url "git@github.com:cognitect/transit-cljs.git"} 15 | :pom-addition [:developers [:developer 16 | [:name "David Nolen"] 17 | [:email "david.nolen@cognitect.com"] 18 | [:organization "Cognitect"] 19 | [:organizationUrl "http://cognitect.com"]]] 20 | :license {:name "The Apache Software License, Version 2.0" 21 | :url "http://www.apache.org/licenses/LICENSE-2.0.txt" 22 | :distribution :repo} 23 | 24 | :source-paths ["src"] 25 | 26 | :clean-targets ["target"] 27 | 28 | :cljsbuild { 29 | :builds [{:id "dev" 30 | :source-paths ["src"] 31 | :compiler { 32 | :output-to "target/transit.dev.js" 33 | :output-dir "target/out-dev" 34 | :optimizations :none 35 | :source-map true}} 36 | {:id "test-dev" 37 | :source-paths ["src" "test/transit/test"] 38 | :compiler { 39 | :output-to "target/transit.test.js" 40 | :output-dir "target/out-dev-test" 41 | :optimizations :none 42 | :source-map true}} 43 | {:id "test" 44 | :source-paths ["src" "test/transit/test"] 45 | :notify-command ["node" "target/transit.test.js"] 46 | :compiler { 47 | :output-to "target/transit.test.js" 48 | :output-dir "target/out-test" 49 | :optimizations :advanced 50 | :pretty-print false 51 | :target :nodejs}} 52 | {:id "roundtrip" 53 | :source-paths ["src" "test/transit/roundtrip"] 54 | :compiler { 55 | :output-to "target/roundtrip.js" 56 | :output-dir "target/out-roundtrip" 57 | :optimizations :advanced 58 | :externs ["resources/node_externs.js"]}} 59 | {:id "bench" 60 | :source-paths ["src" "bench"] 61 | :compiler { 62 | :output-to "target/transit.bench.js" 63 | :output-dir "target/out-bench" 64 | :optimizations :advanced 65 | :pretty-print false 66 | :externs ["resources/node_externs.js"]}} 67 | {:id "adv" 68 | :source-paths ["src"] 69 | :compiler { 70 | :output-to "target/transit.adv.js" 71 | :output-dir "target/out-adv" 72 | :optimizations :advanced 73 | :pretty-print false}}]} 74 | 75 | :codox {:language :clojurescript 76 | :output-path "doc" 77 | :source-uri "https://github.com/cognitect/transit-cljs/blob/master/{filepath}#L{line}"} 78 | ) 79 | -------------------------------------------------------------------------------- /resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/index_dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/integer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/node_externs.js: -------------------------------------------------------------------------------- 1 | var require = function() {}; 2 | var fs = {}; 3 | fs.readFileSync = function() {}; 4 | var process = {}; 5 | process.argv = []; 6 | process.stdin = {}; 7 | process.stdin.on = {}; 8 | process.stdout = {}; 9 | -------------------------------------------------------------------------------- /resources/test.edn: -------------------------------------------------------------------------------- 1 | {:optimizations :advanced 2 | :main transit.test-runner 3 | :output-to "target/transit_test.js" 4 | :output-dir "target" 5 | :output-wrapper true 6 | :verbose true 7 | :compiler-stats true 8 | :parallel-build true} 9 | -------------------------------------------------------------------------------- /script/build.clj: -------------------------------------------------------------------------------- 1 | (require '[cljs.build.api :as b]) 2 | 3 | (b/build (b/inputs "src" "test") 4 | {:output-to "target/transit.test.js" 5 | :output-dir "target/out-test" 6 | :optimizations :simple 7 | :verbose true 8 | :closure-warnings 9 | {:check-types :error 10 | :externs-validation :off 11 | :check-useless-code :off 12 | :missing-properties :off 13 | :undefined-names :off}}) 14 | 15 | (System/exit 0) -------------------------------------------------------------------------------- /script/repl.clj: -------------------------------------------------------------------------------- 1 | (require '[cljs.repl :as repl]) 2 | (require '[cljs.repl.node :as node]) 3 | 4 | (repl/repl (node/repl-env) 5 | :verbose true) -------------------------------------------------------------------------------- /src/cognitect/transit.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright 2014-2022 Cognitect. All Rights Reserved. 2 | ;; 3 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ;; you may not use this file except in compliance with the License. 5 | ;; You may obtain a copy of the License at 6 | ;; 7 | ;; http://www.apache.org/licenses/LICENSE-2.0 8 | ;; 9 | ;; Unless required by applicable law or agreed to in writing, software 10 | ;; distributed under the License is distributed on an "AS-IS" BASIS, 11 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ;; See the License for the specific language governing permissions and 13 | ;; limitations under the License. 14 | 15 | (ns cognitect.transit 16 | (:refer-clojure :exclude [integer? uuid uuid? uri?]) 17 | (:require [clojure.set :as set] 18 | [com.cognitect.transit :as t] 19 | [com.cognitect.transit.types :as ty] 20 | [com.cognitect.transit.eq :as eq] 21 | [goog.object :as gobj]) 22 | (:import [goog.math Long])) 23 | 24 | ;; patch cljs.core/UUID IEquiv 25 | 26 | (extend-type UUID 27 | IEquiv 28 | (-equiv [this other] 29 | (cond 30 | (instance? UUID other) 31 | (identical? (.-uuid this) (.-uuid other)) 32 | 33 | (instance? ty/UUID other) 34 | (identical? (.-uuid this) (.toString other)) 35 | 36 | :else false))) 37 | 38 | (extend-protocol IComparable 39 | UUID 40 | (-compare [this other] 41 | (if (or (instance? UUID other) 42 | (instance? ty/UUID other)) 43 | (compare (.toString this) (.toString other)) 44 | (throw (js/Error. (str "Cannot compare " this " to " other))))) 45 | ty/UUID 46 | (-compare [this other] 47 | (if (or (instance? UUID other) 48 | (instance? ty/UUID other)) 49 | (compare (.toString this) (.toString other)) 50 | (throw (js/Error. (str "Cannot compare " this " to " other)))))) 51 | 52 | (extend-protocol IEquiv 53 | Long 54 | (-equiv [this other] 55 | (.equiv this other)) 56 | 57 | ty/UUID 58 | (-equiv [this other] 59 | (if (instance? UUID other) 60 | (-equiv other this) 61 | (.equiv this other))) 62 | 63 | ty/TaggedValue 64 | (-equiv [this other] 65 | (.equiv this other))) 66 | 67 | (extend-protocol IHash 68 | Long 69 | (-hash [this] 70 | (eq/hashCode this)) 71 | 72 | ty/UUID 73 | (-hash [this] 74 | (hash (.toString this))) 75 | 76 | ty/TaggedValue 77 | (-hash [this] 78 | (eq/hashCode this))) 79 | 80 | (extend-type ty/UUID 81 | IUUID 82 | IPrintWithWriter 83 | (-pr-writer [uuid writer _] 84 | (-write writer (str "#uuid \"" (.toString uuid) "\"")))) 85 | 86 | (defn ^:no-doc opts-merge [a b] 87 | (doseq [k (js-keys b)] 88 | (let [v (gobj/get b k)] 89 | (gobj/set a k v))) 90 | a) 91 | 92 | (deftype ^:no-doc MapBuilder [] 93 | Object 94 | (init [_ node] (transient {})) 95 | (add [_ m k v node] (assoc! m k v)) 96 | (finalize [_ m node] (persistent! m)) 97 | (fromArray [_ arr node] (cljs.core/PersistentArrayMap.fromArray arr true true))) 98 | 99 | (deftype ^:no-doc VectorBuilder [] 100 | Object 101 | (init [_ node] (transient [])) 102 | (add [_ v x node] (conj! v x)) 103 | (finalize [_ v node] (persistent! v)) 104 | (fromArray [_ arr node] (cljs.core/PersistentVector.fromArray arr true))) 105 | 106 | (defn reader 107 | "Return a transit reader. type may be either :json or :json-verbose. 108 | opts may be a map optionally containing a :handlers entry. The value 109 | of :handlers should be map from string tag to a decoder function of one 110 | argument which returns the in-memory representation of the semantic transit 111 | value. If a :default handler is provided, it will be used when no matching 112 | read handler can be found." 113 | ([type] (reader type nil)) 114 | ([type opts] 115 | (t/reader (name type) 116 | (opts-merge 117 | #js {:handlers 118 | (clj->js 119 | (merge 120 | {"$" (fn [v] (symbol v)) 121 | ":" (fn [v] (keyword v)) 122 | "set" (fn [v] (into #{} v)) 123 | "list" (fn [v] (into () (.reverse v))) 124 | "cmap" (fn [v] 125 | (loop [i 0 ret (transient {})] 126 | (if (< i (alength v)) 127 | (recur (+ i 2) 128 | (assoc! ret (aget v i) (aget v (inc i)))) 129 | (persistent! ret)))) 130 | "with-meta" 131 | (fn [v] (with-meta (aget v 0) (aget v 1)))} 132 | (dissoc (:handlers opts) :default))) 133 | :defaultHandler (-> opts :handlers :default) 134 | :mapBuilder (MapBuilder.) 135 | :arrayBuilder (VectorBuilder.) 136 | :preferStrings false 137 | :preferBuffers false} 138 | (clj->js 139 | (set/rename-keys 140 | (dissoc opts :handlers) 141 | {:array-builder :arrayBuilder 142 | :map-builder :mapBuilder 143 | :prefer-strings :preferStrings 144 | :prefer-buffers :preferBuffers})))))) 145 | 146 | (defn read 147 | "Read a transit encoded string into ClojureScript values given a 148 | transit reader." 149 | [r str] 150 | (.read r str)) 151 | 152 | (deftype ^:no-doc KeywordHandler [] 153 | Object 154 | (tag [_ v] ":") 155 | (rep [_ v] (.-fqn v)) 156 | (stringRep [_ v] (.-fqn v))) 157 | 158 | (deftype ^:no-doc SymbolHandler [] 159 | Object 160 | (tag [_ v] "$") 161 | (rep [_ v] (.-str v)) 162 | (stringRep [_ v] (.-str v))) 163 | 164 | (deftype ^:no-doc ListHandler [] 165 | Object 166 | (tag [_ v] "list") 167 | (rep [_ v] 168 | (let [ret #js []] 169 | (doseq [x v] (.push ret x)) 170 | (t/tagged "array" ret))) 171 | (stringRep [_ v] nil)) 172 | 173 | (deftype ^:no-doc MapHandler [] 174 | Object 175 | (tag [_ v] "map") 176 | (rep [_ v] v) 177 | (stringRep [_ v] nil)) 178 | 179 | (deftype ^:no-doc SetHandler [] 180 | Object 181 | (tag [_ v] "set") 182 | (rep [_ v] 183 | (let [ret #js []] 184 | (doseq [x v] (.push ret x)) 185 | (t/tagged "array" ret))) 186 | (stringRep [v] nil)) 187 | 188 | (deftype ^:no-doc VectorHandler [] 189 | Object 190 | (tag [_ v] "array") 191 | (rep [_ v] 192 | (let [ret #js []] 193 | (doseq [x v] (.push ret x)) 194 | ret)) 195 | (stringRep [_ v] nil)) 196 | 197 | (deftype ^:no-doc UUIDHandler [] 198 | Object 199 | (tag [_ v] "u") 200 | (rep [_ v] (.-uuid v)) 201 | (stringRep [this v] (.rep this v))) 202 | 203 | (deftype ^:no-doc WithMeta [value meta]) 204 | 205 | (deftype ^:no-doc WithMetaHandler [] 206 | Object 207 | (tag [_ v] "with-meta") 208 | (rep [_ v] 209 | (t/tagged "array" #js [(.-value v) (.-meta v)])) 210 | (stringRep [_ v] nil)) 211 | 212 | (defn writer 213 | "Return a transit writer. type maybe either :json or :json-verbose. 214 | opts is a map with the following optional keys: 215 | 216 | :handlers - a map of type constructors to handler instances. Can optionally 217 | provide a :default write handler which will be used if no 218 | matching handler can be found. 219 | :transform - a function of one argument returning a transformed value. Will 220 | be invoked on a value before it is written." 221 | ([type] (writer type nil)) 222 | ([type opts] 223 | (let [keyword-handler (KeywordHandler.) 224 | symbol-handler (SymbolHandler.) 225 | list-handler (ListHandler.) 226 | map-handler (MapHandler.) 227 | set-handler (SetHandler.) 228 | vector-handler (VectorHandler.) 229 | uuid-handler (UUIDHandler.) 230 | meta-handler (WithMetaHandler.) 231 | handlers 232 | (merge 233 | {cljs.core/Keyword keyword-handler 234 | cljs.core/Symbol symbol-handler 235 | cljs.core/Range list-handler 236 | cljs.core/List list-handler 237 | cljs.core/Cons list-handler 238 | cljs.core/EmptyList list-handler 239 | cljs.core/LazySeq list-handler 240 | cljs.core/RSeq list-handler 241 | cljs.core/IndexedSeq list-handler 242 | cljs.core/ChunkedCons list-handler 243 | cljs.core/ChunkedSeq list-handler 244 | cljs.core/PersistentQueueSeq list-handler 245 | cljs.core/PersistentQueue list-handler 246 | cljs.core/PersistentArrayMapSeq list-handler 247 | cljs.core/PersistentTreeMapSeq list-handler 248 | cljs.core/NodeSeq list-handler 249 | cljs.core/ArrayNodeSeq list-handler 250 | cljs.core/KeySeq list-handler 251 | cljs.core/ValSeq list-handler 252 | cljs.core/PersistentArrayMap map-handler 253 | cljs.core/PersistentHashMap map-handler 254 | cljs.core/PersistentTreeMap map-handler 255 | cljs.core/PersistentHashSet set-handler 256 | cljs.core/PersistentTreeSet set-handler 257 | cljs.core/PersistentVector vector-handler 258 | cljs.core/Subvec vector-handler 259 | cljs.core/UUID uuid-handler 260 | cljs.core/BlackNode vector-handler 261 | cljs.core/RedNode vector-handler 262 | WithMeta meta-handler} 263 | (when (exists? cljs.core/Eduction) 264 | {^:cljs.analyzer/no-resolve cljs.core/Eduction list-handler}) 265 | (when (exists? cljs.core/Repeat) 266 | {^:cljs.analyzer/no-resolve cljs.core/Repeat list-handler}) 267 | (when (exists? cljs.core/MapEntry) 268 | {^:cljs.analyzer/no-resolve cljs.core/MapEntry vector-handler}) 269 | (:handlers opts))] 270 | (t/writer (name type) 271 | (opts-merge 272 | #js {:objectBuilder 273 | (fn [m kfn vfn] 274 | (reduce-kv 275 | (fn [obj k v] 276 | (doto obj (.push (kfn k) (vfn v)))) 277 | #js ["^ "] m)) 278 | :handlers 279 | (specify handlers 280 | Object 281 | (forEach 282 | ([coll f] 283 | (doseq [[k v] coll] 284 | (if (= :default k) 285 | (f v "default") 286 | (f v k)))))) 287 | :unpack 288 | (fn [x] 289 | (if (instance? cljs.core/PersistentArrayMap x) 290 | (.-arr x) 291 | false))} 292 | (clj->js (dissoc opts :handlers))))))) 293 | 294 | (defn write 295 | "Encode an object into a transit string given a transit writer." 296 | [w o] 297 | (.write w o)) 298 | 299 | (defn read-handler 300 | "Construct a read handler. Implemented as identity, exists primarily 301 | for API compatiblity with transit-clj" 302 | [from-rep] 303 | from-rep) 304 | 305 | (defn- fn-or-val 306 | [f] 307 | (if (fn? f) f (constantly f))) 308 | 309 | (defn write-handler 310 | "Creates a transit write handler whose tag, rep, 311 | stringRep, and verboseWriteHandler methods 312 | invoke the provided fns." 313 | ([tag-fn rep-fn] 314 | (write-handler tag-fn rep-fn nil nil)) 315 | ([tag-fn rep-fn str-rep-fn] 316 | (write-handler tag-fn rep-fn str-rep-fn nil)) 317 | ([tag-fn rep-fn str-rep-fn verbose-handler-fn] 318 | (let [tag-fn (fn-or-val tag-fn) 319 | rep-fn (fn-or-val rep-fn) 320 | str-rep-fn (fn-or-val str-rep-fn) 321 | verbose-handler-fn (fn-or-val verbose-handler-fn)] 322 | (reify 323 | Object 324 | (tag [_ o] (tag-fn o)) 325 | (rep [_ o] (rep-fn o)) 326 | (stringRep [_ o] (when str-rep-fn (str-rep-fn o))) 327 | (getVerboseHandler [_] (when verbose-handler-fn (verbose-handler-fn))))))) 328 | 329 | ;; ============================================================================= 330 | ;; Constructors & Predicates 331 | 332 | (defn tagged-value 333 | "Construct a tagged value. tag must be a string and rep can 334 | be any transit encodeable value." 335 | [tag rep] 336 | (ty/taggedValue tag rep)) 337 | 338 | (defn tagged-value? 339 | "Returns true if x is a transit tagged value, false otherwise." 340 | [x] 341 | (ty/isTaggedValue x)) 342 | 343 | (defn integer 344 | "Construct a transit integer value. Returns JavaScript number if 345 | in the 53bit integer range, a goog.math.Long instance if above. s 346 | may be a string or a JavaScript number." 347 | [s] 348 | (ty/intValue s)) 349 | 350 | (defn integer? 351 | "Returns true if x is an integer value between the 53bit and 64bit 352 | range, false otherwise." 353 | [x] 354 | (ty/isInteger x)) 355 | 356 | (defn bigint 357 | "Construct a big integer from a string." 358 | [s] 359 | (ty/bigInteger s)) 360 | 361 | (defn bigint? 362 | "Returns true if x is a transit big integer value, false otherwise." 363 | [x] 364 | (ty/isBigInteger x)) 365 | 366 | (defn bigdec 367 | "Construct a big decimal from a string." 368 | [s] 369 | (ty/bigDecimalValue s)) 370 | 371 | (defn bigdec? 372 | "Returns true if x is a transit big decimal value, false otherwise." 373 | [x] 374 | (ty/isBigDecimal x)) 375 | 376 | (defn uri 377 | "Construct a URI from a string." 378 | [s] 379 | (ty/uri s)) 380 | 381 | (defn uri? 382 | "Returns true if x is a transit URI value, false otherwise." 383 | [x] 384 | (ty/isURI x)) 385 | 386 | (defn uuid 387 | "Construct a UUID from a string." 388 | [s] 389 | (ty/uuid s)) 390 | 391 | (defn uuid? 392 | "Returns true if x is a transit UUID value, false otherwise." 393 | [x] 394 | (or (ty/isUUID x) (instance? UUID x))) 395 | 396 | (defn binary 397 | "Construct a transit binary value. s should be base64 encoded 398 | string." 399 | [s] 400 | (ty/binary s)) 401 | 402 | (defn binary? 403 | "Returns true if x is a transit binary value, false otherwise." 404 | [x] 405 | (ty/isBinary x)) 406 | 407 | (defn quoted 408 | "Construct a quoted transit value. x should be a transit 409 | encodeable value." 410 | [x] 411 | (ty/quoted x)) 412 | 413 | (defn quoted? 414 | "Returns true if x is a transit quoted value, false otherwise." 415 | [x] 416 | (ty/isQuoted x)) 417 | 418 | (defn link 419 | "Construct a transit link value. x should be an IMap instance 420 | containing at a minimum the following keys: :href, :rel. It 421 | may optionall include :name, :render, and :prompt. :href must 422 | be a transit URI, all other values are strings, and :render must 423 | be either :image or :link." 424 | [x] 425 | (ty/link x)) 426 | 427 | (defn link? 428 | "Returns true if x a transit link value, false if otherwise." 429 | [x] 430 | (ty/isLink x)) 431 | 432 | (defn write-meta 433 | "For :transform. Will write any metadata present on the value." 434 | [x] 435 | (if (implements? IMeta x) 436 | (let [m (-meta ^not-native x)] 437 | (if-not (nil? m) 438 | (WithMeta. (-with-meta ^not-native x nil) m) 439 | x)) 440 | x)) 441 | -------------------------------------------------------------------------------- /test/transit/roundtrip/core.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright 2014 Cognitect. All Rights Reserved. 2 | ;; 3 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ;; you may not use this file except in compliance with the License. 5 | ;; You may obtain a copy of the License at 6 | ;; 7 | ;; http://www.apache.org/licenses/LICENSE-2.0 8 | ;; 9 | ;; Unless required by applicable law or agreed to in writing, software 10 | ;; distributed under the License is distributed on an "AS-IS" BASIS, 11 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ;; See the License for the specific language governing permissions and 13 | ;; limitations under the License. 14 | 15 | (ns transit.roundtrip.core 16 | (:require [cognitect.transit :as t])) 17 | 18 | (def transport (or (aget (.-argv js/process) 2) :json)) 19 | (def r (t/reader transport)) 20 | (def w (t/writer transport)) 21 | 22 | (.on (.-stdin js/process) "data" 23 | (fn [data err] 24 | (.write (.-stdout js/process) (.write w (.read r data))))) 25 | -------------------------------------------------------------------------------- /test/transit/test/core.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright 2014 Cognitect. All Rights Reserved. 2 | ;; 3 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ;; you may not use this file except in compliance with the License. 5 | ;; You may obtain a copy of the License at 6 | ;; 7 | ;; http://www.apache.org/licenses/LICENSE-2.0 8 | ;; 9 | ;; Unless required by applicable law or agreed to in writing, software 10 | ;; distributed under the License is distributed on an "AS-IS" BASIS, 11 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ;; See the License for the specific language governing permissions and 13 | ;; limitations under the License. 14 | 15 | (ns transit.test.core 16 | (:require [cognitect.transit :as t] 17 | [cljs.test :as test :refer-macros [deftest is run-tests testing]])) 18 | 19 | (enable-console-print!) 20 | 21 | (def r (t/reader :json)) 22 | (def w (t/writer :json)) 23 | 24 | (deftest test-basic-write 25 | (testing "Testing basic Transit write" 26 | (is (= (t/write w 1) "[\"~#'\",1]")) 27 | (is (= (t/write w (js/Date. 1399471321791)) "[\"~#'\",\"~m1399471321791\"]")) 28 | (is (= (t/write w {:foo "bar"}) "[\"^ \",\"~:foo\",\"bar\"]")) 29 | (is (= (t/write w [1 2 3]) "[1,2,3]")) 30 | ;;(is (= (t/write w #{1 2 3}) "{\"~#set\":[1,2,3]}")) 31 | (is (= (t/write w '(1 2 3)) "[\"~#list\",[1,2,3]]")) 32 | (is (= (t/write w (reverse [1 2 3])) "[\"~#list\",[3,2,1]]")) 33 | (is (= (t/write w (range 3)) "[\"~#list\",[0,1,2]]")) 34 | (is (= (t/write w (take 3 (repeat true))) "[\"~#list\",[true,true,true]]")) 35 | (is (= (t/write w #js [1 2 3]) "[1,2,3]")) 36 | (is (= (t/write w #js {"foo" "bar"}) "[\"^ \",\"foo\",\"bar\"]")))) 37 | 38 | (deftest test-basic-read 39 | (testing "Testing basic Transit read" 40 | (is (= (t/read r "{\"~#'\":1}") 1)) 41 | (is (= (t/read r "{\"~:foo\":\"bar\"}") {:foo "bar"})) 42 | (is (= (t/read r "[1,2,3]") [1 2 3])) 43 | (is (= (t/read r "[\"~#set\",[1,2,3]]") #{1 2 3})) 44 | (is (= (t/read r "[\"~#list\",[1,2,3]]") '(1 2 3))) 45 | (is (= (.valueOf (t/read r "{\"~#'\":\"~t2014-05-07T14:02:01.791Z\"}")) 46 | (.valueOf (js/Date. 1399471321791)))))) 47 | 48 | (defn roundtrip [s] 49 | (t/write w (t/read r s))) 50 | 51 | (deftest test-roundtrip 52 | (testing "Testing round tripping" 53 | (is (= (roundtrip "[\"~:foo\",\"~:bar\",[\"^ \",\"^1\",[1,2]]]") 54 | "[\"~:foo\",\"~:bar\",[\"^ \",\"^1\",[1,2]]]")) 55 | (is (= (roundtrip "[\"~#point\",[1,2]]") 56 | "[\"~#point\",[1,2]]")) 57 | (is (= (roundtrip "[\"^ \",\"foo\",\"~xfoo\"]") 58 | "[\"^ \",\"foo\",\"~xfoo\"]")) 59 | (is (= (roundtrip "[\"^ \",\"~/t\",null]") 60 | "[\"^ \",\"~/t\",null]")) 61 | (is (= (roundtrip "[\"^ \",\"~/f\",null]") 62 | "[\"^ \",\"~/f\",null]")) 63 | (is (= (roundtrip "{\"~#'\":\"~f-1.1E-1\"}") 64 | "[\"~#'\",\"~f-1.1E-1\"]")) 65 | (is (= (roundtrip "{\"~#'\":\"~f-1.10E-1\"}") 66 | "[\"~#'\",\"~f-1.10E-1\"]")) 67 | (is (= (roundtrip "[\"~#set\",[[\"~#ratio\",[\"~i4953778853208128465\",\"~i636801457410081246\"]],[\"^1\",[\"~i-8516423834113052903\",\"~i5889347882583416451\"]]]]") 68 | "[\"~#set\",[[\"~#ratio\",[\"~i4953778853208128465\",\"~i636801457410081246\"]],[\"^1\",[\"~i-8516423834113052903\",\"~i5889347882583416451\"]]]]")) 69 | (is (= (roundtrip "[[\"^ \",\"aaaa\",1,\"bbbb\",2],[\"^ \",\"^0\",3,\"^1\",4],[\"^ \",\"^0\",5,\"^1\",6]]") 70 | "[[\"^ \",\"aaaa\",1,\"bbbb\",2],[\"^ \",\"^0\",3,\"^1\",4],[\"^ \",\"^0\",5,\"^1\",6]]")) 71 | (is (= (roundtrip "{\"~#'\":\"~n8987676543234565432178765987645654323456554331234566789\"}") 72 | "[\"~#'\",\"~n8987676543234565432178765987645654323456554331234566789\"]")) 73 | (is (= (roundtrip "[\"~#list\",[0,1,2,true,false,\"five\",\"~:six\",\"~$seven\",\"~~eight\",null]]") 74 | "[\"~#list\",[0,1,2,true,false,\"five\",\"~:six\",\"~$seven\",\"~~eight\",null]]")) 75 | ;; (is (= (roundtrip "[\"^ \",\"~:key0000\",0,\"~:key0001\",1,\"~:key0002\",2,\"~:key0003\",3,\"~:key0004\",4,\"~:key0005\",5,\"~:key0006\",6,\"~:key0007\",7,\"~:key0008\",8,\"~:key0009\",9]") 76 | ;; "[\"^ \",\"~:key0000\",0,\"~:key0001\",1,\"~:key0002\",2,\"~:key0003\",3,\"~:key0004\",4,\"~:key0005\",5,\"~:key0006\",6,\"~:key0007\",7,\"~:key0008\",8,\"~:key0009\",9]")) 77 | )) 78 | 79 | ;; cmap 80 | (def cmap 81 | (->> {[] 42} 82 | (t/write (t/writer :json)) 83 | (t/read (t/reader :json)))) 84 | 85 | (deftest test-cmap 86 | (is (satisfies? cljs.core/IMap cmap)) 87 | (is (= cmap {[] 42}))) 88 | 89 | (deftest test-constructor-and-predicates-api 90 | (testing "Testing constructor & predicates API" 91 | (let [p0 (t/read r "{\"~#point\":[1.5,2.5]}") 92 | p1 (t/read r "{\"~#point\":[1.5,2.5]}") 93 | m0 {p0 :foo}] 94 | (is (t/tagged-value? p0)) 95 | (is (= p0 p1)) 96 | (is (= (get m0 p0) :foo))) 97 | (let [uuid0 (t/read r "{\"~#'\":\"~u2f9e540c-0591-eff5-4e77-267b2cb3951f\"}") 98 | uuid1 (t/read r "{\"~#'\":\"~u2f9e540c-0591-eff5-4e77-267b2cb3951f\"}") 99 | m1 {uuid0 :bar}] 100 | (is (t/uuid? uuid0)) 101 | (is (uuid? uuid0)) 102 | (is (= uuid0 uuid1)) 103 | (is (= (get m1 uuid0) :bar))) 104 | (let [l0 (t/read r "{\"~#'\":\"~i9007199254740993\"}") 105 | m2 {l0 :baz}] 106 | (is (t/integer? l0)) 107 | (is (= (get m2 l0) :baz))))) 108 | 109 | ;; TCLJS-3 110 | (deftest test-tcljs3 111 | (is (= (t/read (t/reader :json {:handlers {"custom" (fn [x] x)}}) "[\"~:foo\", 1]") 112 | [:foo 1]))) 113 | 114 | (defrecord Point [x y]) 115 | 116 | (deftype PointHandler [] 117 | Object 118 | (tag [_ v] "point") 119 | (rep [_ v] #js [(.-x v) (.-y v)]) 120 | (stringRep [_ v] nil)) 121 | 122 | (def cr 123 | (t/reader :json 124 | {:handlers 125 | {"custom" (fn [x] x) 126 | "point" (fn [[x y]] (Point. x y))}})) 127 | 128 | (deftest test-read-custom-tags 129 | (is (= (t/read cr "[\"~#point\",[1.5,2.5]]") 130 | (Point. 1.5 2.5))) 131 | (is (= (t/read cr "[\"~:foo\", 1]") 132 | [:foo 1]))) 133 | 134 | (def cw 135 | (t/writer :json 136 | {:handlers 137 | {Point (PointHandler.)}})) 138 | 139 | (deftest test-write-custom-tags 140 | (is (= (t/write cw (Point. 1.5 2.5)) 141 | "[\"~#point\",[1.5,2.5]]")) ) 142 | 143 | ;; CLJS UUID 144 | 145 | (deftest test-uuid 146 | (is (= (t/read r "{\"~#'\":\"~u550e8400-e29b-41d4-a716-446655440000\"}") 147 | #uuid "550e8400-e29b-41d4-a716-446655440000")) 148 | (is (= (hash (t/read r "{\"~#'\":\"~u550e8400-e29b-41d4-a716-446655440000\"}")) 149 | (hash #uuid "550e8400-e29b-41d4-a716-446655440000"))) 150 | (is (= #uuid "550e8400-e29b-41d4-a716-446655440000" 151 | (t/read r "{\"~#'\":\"~u550e8400-e29b-41d4-a716-446655440000\"}"))) 152 | (is (= (t/write w #uuid "550e8400-e29b-41d4-a716-446655440000") 153 | "[\"~#'\",\"~u550e8400-e29b-41d4-a716-446655440000\"]"))) 154 | 155 | ;; Transit UUID printing 156 | 157 | (deftest test-uuid-print 158 | (is (= (pr-str (t/read r "{\"~#'\":\"~u550e8400-e29b-41d4-a716-446655440000\"}")) 159 | (pr-str #uuid "550e8400-e29b-41d4-a716-446655440000")))) 160 | 161 | ;; Test UUID comparison 162 | 163 | (deftest test-uuid-compare 164 | (is (zero? 165 | (compare (t/read r "{\"~#'\":\"~u550e8400-e29b-41d4-a716-446655440000\"}") 166 | #uuid "550e8400-e29b-41d4-a716-446655440000")))) 167 | 168 | (deftest test-integer 169 | (is (= (t/integer "30") 30))) 170 | 171 | ;; TCLJS-22 172 | 173 | (deftest test-tcljs-22 174 | (let [w (t/writer :json) 175 | r (t/reader :json) 176 | pathological [{:any-value {["this vector makes this a cmap"] "any value" "any string" :victim}} 177 | {:victim :any-other-value}]] 178 | (is (= pathological 179 | (t/read r (t/write w pathological)))))) 180 | 181 | (deftest test-tcljs-33 182 | (let [w (t/writer :json) 183 | r (t/reader :json) 184 | me (first {:foo 1})] 185 | (is (= [:foo 1] (t/read r (t/write w me)))))) 186 | 187 | (deftest test-tcljs-44 188 | (let [w (t/writer :json) 189 | r (t/reader :json) 190 | xs (eduction (take 3) (range))] 191 | (is (= (seq xs) (t/read r (t/write w xs)))))) 192 | 193 | (deftest test-tcljs-45 194 | (let [w (t/writer :json) 195 | r (t/reader :json) 196 | xs (repeat 3 :hi)] 197 | (is (= xs (t/read r (t/write w xs)))))) 198 | 199 | (deftest test-meta 200 | (let [mw (t/writer :json {:transform t/write-meta}) 201 | xs (with-meta [1 2 3] {:text "cool!"}) 202 | xs' (t/read r (t/write mw xs)) 203 | m {:baz xs} 204 | m' (t/read r (t/write mw m))] 205 | (is (= [1 2 3] xs')) 206 | (is (= {:text "cool!"} (meta xs'))) 207 | (is (= {:baz [1 2 3]} m')) 208 | (is (= {:text "cool!"} (-> m' :baz meta))))) 209 | 210 | (deftype DefaultHandler [] 211 | Object 212 | (tag [_ v] "unknown") 213 | (rep [_ v] (when v (.toString v)))) 214 | 215 | (deftest test-default-writer 216 | (let [w (t/writer :json {:handlers {:default (DefaultHandler.)}})] 217 | (is (= (t/write w (Point. 1 2)) "[\"~#unknown\",\"[object Object]\"]")))) 218 | 219 | (deftest test-default-reader 220 | (let [r (t/reader :json 221 | {:handlers 222 | {:default (fn [tag value] (t/tagged-value tag value))}})] 223 | (is (t/tagged-value? (first (t/read r "[\"~q1\"]")))))) 224 | 225 | (deftest test-tcljs-58 226 | (testing "write handlers can take values for config" 227 | (let [sorted-set-write-handler (t/write-handler "sorted-set" (fn [o] (vec o))) 228 | w (t/writer :json-verbose 229 | {:handlers {cljs.core/PersistentTreeSet sorted-set-write-handler}})] 230 | (is (= "{\"~#sorted-set\":[1,2,3,4]}" 231 | (t/write w (sorted-set 3 4 1 2))))))) 232 | 233 | (deftest test-tcljs-50 234 | (testing "sorted maps cannot be written" 235 | (let [w (t/writer :json) 236 | r (t/reader :json)] 237 | (is (= {:a 1} (t/read r (t/write w (sorted-map :a 1)))))))) 238 | 239 | (defn -main [& args] 240 | (run-tests)) 241 | 242 | (set! *main-cli-fn* -main) 243 | 244 | (comment 245 | 246 | (run-tests) 247 | 248 | ) 249 | -------------------------------------------------------------------------------- /test/transit/test_runner.cljs: -------------------------------------------------------------------------------- 1 | (ns transit.test-runner 2 | (:require [cljs.test :refer [run-tests]] 3 | [transit.test.core])) 4 | 5 | (set! *print-newline* false) 6 | 7 | (if (exists? js/print) 8 | (set-print-fn! js/print) 9 | (enable-console-print!)) 10 | 11 | (run-tests 'transit.test.core) 12 | --------------------------------------------------------------------------------