├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── appveyor.yml
├── ci
├── before_deploy.ps1
├── before_deploy.sh
├── install.sh
└── script.sh
├── etc
├── example.jsd
└── example.json
└── src
├── compiler.rs
├── formatter.rs
├── main.rs
└── parser.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | **/*.rs.bk
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Based on the "trust" template v0.1.2
2 | # https://github.com/japaric/trust/tree/v0.1.2
3 |
4 | dist: bionic
5 | language: rust
6 | services: docker
7 | sudo: required
8 |
9 | # TODO Rust builds on stable by default, this can be
10 | # overridden on a case by case basis down below.
11 |
12 | env:
13 | global:
14 | # TODO Update this to match the name of your project.
15 | - CRATE_NAME=chema
16 |
17 | matrix:
18 | # TODO These are all the build jobs. Adjust as necessary. Comment out what you
19 | # don't need
20 | include:
21 | # Android
22 | # - env: TARGET=aarch64-linux-android DISABLE_TESTS=1
23 | # - env: TARGET=arm-linux-androideabi DISABLE_TESTS=1
24 | # - env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1
25 | # - env: TARGET=i686-linux-android DISABLE_TESTS=1
26 | # - env: TARGET=x86_64-linux-android DISABLE_TESTS=1
27 |
28 | # iOS
29 | # - env: TARGET=aarch64-apple-ios DISABLE_TESTS=1
30 | # os: osx
31 | # - env: TARGET=armv7-apple-ios DISABLE_TESTS=1
32 | # os: osx
33 | # - env: TARGET=armv7s-apple-ios DISABLE_TESTS=1
34 | # os: osx
35 | # - env: TARGET=i386-apple-ios DISABLE_TESTS=1
36 | # os: osx
37 | # - env: TARGET=x86_64-apple-ios DISABLE_TESTS=1
38 | # os: osx
39 |
40 | # Linux
41 | - env: TARGET=aarch64-unknown-linux-gnu
42 | - env: TARGET=arm-unknown-linux-gnueabi
43 | - env: TARGET=armv7-unknown-linux-gnueabihf
44 | - env: TARGET=i686-unknown-linux-gnu
45 | - env: TARGET=i686-unknown-linux-musl
46 | # - env: TARGET=mips-unknown-linux-gnu
47 | # - env: TARGET=mips64-unknown-linux-gnuabi64
48 | # - env: TARGET=mips64el-unknown-linux-gnuabi64
49 | # - env: TARGET=mipsel-unknown-linux-gnu
50 | # - env: TARGET=powerpc-unknown-linux-gnu
51 | # - env: TARGET=powerpc64-unknown-linux-gnu
52 | # - env: TARGET=powerpc64le-unknown-linux-gnu
53 | # - env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
54 | - env: TARGET=x86_64-unknown-linux-gnu
55 | - env: TARGET=x86_64-unknown-linux-musl
56 |
57 | # OSX
58 | - env: TARGET=i686-apple-darwin
59 | os: osx
60 | - env: TARGET=x86_64-apple-darwin
61 | os: osx
62 |
63 | # *BSD
64 | - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
65 | - env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
66 | - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
67 |
68 | # Windows
69 | # - env: TARGET=x86_64-pc-windows-gnu
70 |
71 | # Bare metal
72 | # These targets don't support std and as such are likely not suitable for
73 | # most crates.
74 | # - env: TARGET=thumbv6m-none-eabi
75 | # - env: TARGET=thumbv7em-none-eabi
76 | # - env: TARGET=thumbv7em-none-eabihf
77 | # - env: TARGET=thumbv7m-none-eabi
78 |
79 | # Testing other channels
80 | - env: TARGET=x86_64-unknown-linux-gnu
81 | rust: nightly
82 | - env: TARGET=x86_64-apple-darwin
83 | os: osx
84 | rust: nightly
85 |
86 | before_install:
87 | - set -e
88 | - rustup self update
89 |
90 | install:
91 | - sh ci/install.sh
92 | - source ~/.cargo/env || true
93 |
94 | script:
95 | - bash ci/script.sh
96 |
97 | after_script: set +e
98 |
99 | before_deploy:
100 | - sh ci/before_deploy.sh
101 |
102 | deploy:
103 | # TODO update `api_key.secure`
104 | # - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
105 | # - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789
106 | # - Paste the output down here
107 | api_key:
108 | secure: "plR86aca4DYP+oB0lKAij+wUqGefuR6Hzfk7iqCprDNLkzBLtmG12+UX0bZ/xsYXYSaLjpTNGS4ynNYNLAO1+DUvK6P/NiUGgjbbqGcolb7p/oW7Ac/YIhjmEyDdD6U488l3e/zDh7dFL0K2yZWnEohfTg43fAcsbK2ZXrRPXLBR1kjOFu5KW6WeEkyVgnbDm9w34wqjbyraLNJYZDMMw9edtwfVoVv2o0fuyOFdcFueDZ+IYfeGHmi7Z6VcuzwPiHMf0d70b5WBA2Lwcotnm6ivMBiczvaz2kKjxsZWHNK8x/EYhiYadX8X0T+d5WhS8fjnywQtApQfxITUIxUhd+tOdXXjfs7LQsouSol87gO02MvFaRqsFwiF3St2jaxnPIa7d4JYzpPoGN3TxjQwnlat8EcTVfujMkwv+Z8111Yi79xcZBa3CVzBb9RYaBn4ode/Ft9kT/tY2RZTjiEMd5q6fIRD6BbtOY8wm1KZGCxplTIUEnoD9sFn7Y5qsvHu1WxC4/o6qlLzDoJ9udM0KxFsuCg+REDp+dZ4Lx51K8ruTeKcG0B+TLZqZraztVzzeX8olLfciva4FVfEL6k1R87b4t5uHc5sKBSQO4q1wjoAMVGxRqF+dEaebF7LXO8MZF18UJecSEIBj7u2jBcbV5XovkQFITMa0jjrLcRaT3M="
109 | file_glob: true
110 | file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.*
111 | on:
112 | # TODO Here you can pick which targets will generate binary releases
113 | # In this example, there are some targets that are tested using the stable
114 | # and nightly channels. This condition makes sure there is only one release
115 | # for such targets and that's generated using the stable channel
116 | condition: $TRAVIS_RUST_VERSION = stable
117 | tags: true
118 | provider: releases
119 | skip_cleanup: true
120 |
121 | cache: cargo
122 | before_cache:
123 | # Travis can't cache files that are not readable by "others"
124 | - chmod -R a+r $HOME/.cargo
125 |
126 | branches:
127 | only:
128 | # release tags
129 | - /^v\d+\.\d+\.\d+.*$/
130 | - master
131 |
132 | notifications:
133 | email:
134 | on_success: never
135 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 0.0.9
2 | ## New Feature
3 |
4 | * Improve error messages
5 | * New syntax: optional field namely `struct { field?: type }`
6 |
7 | ## Internal
8 |
9 | * update combine to 4
10 |
11 | # 0.0.8
12 | ## Bug Fix
13 |
14 | * code generation of `nullable` with reference types are fixed
15 |
16 | ## Internal
17 |
18 | * migrated code base to Rust 2018 Edition
19 |
20 |
21 | # 0.0.7
22 | ## New Feature
23 |
24 | * support `TYPE where PRED` synax
25 | + it looks like `string where 1 <= length && length <= 128 && it =~ /[a-z0-9!"#$%&'()=~|@]+/`
26 |
27 | # 0.0.6
28 | ## New Feature
29 |
30 | * support `url("schema_url")` syntax
31 | * support `--path-prefix` flag
32 |
33 | ## Internal
34 |
35 | * update dependencies
36 |
37 | # 0.0.5
38 |
39 | ???
40 |
41 | # 0.0.4
42 | ## New Feature
43 |
44 | * support format types
45 |
46 | # 0.0.3
47 | ## New Feature
48 |
49 | * support string constant type
50 |
51 | # 0.0.2
52 | ## Bug Fix
53 |
54 | * fix a bug of multiple comment handling
55 |
56 | # 0.0.1
57 | initial release
58 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "aho-corasick"
5 | version = "0.7.15"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
8 | dependencies = [
9 | "memchr",
10 | ]
11 |
12 | [[package]]
13 | name = "ansi_term"
14 | version = "0.11.0"
15 | source = "registry+https://github.com/rust-lang/crates.io-index"
16 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
17 | dependencies = [
18 | "winapi",
19 | ]
20 |
21 | [[package]]
22 | name = "atty"
23 | version = "0.2.14"
24 | source = "registry+https://github.com/rust-lang/crates.io-index"
25 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
26 | dependencies = [
27 | "hermit-abi",
28 | "libc",
29 | "winapi",
30 | ]
31 |
32 | [[package]]
33 | name = "bitflags"
34 | version = "1.2.1"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
37 |
38 | [[package]]
39 | name = "bytes"
40 | version = "0.5.6"
41 | source = "registry+https://github.com/rust-lang/crates.io-index"
42 | checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
43 |
44 | [[package]]
45 | name = "cfg-if"
46 | version = "0.1.10"
47 | source = "registry+https://github.com/rust-lang/crates.io-index"
48 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
49 |
50 | [[package]]
51 | name = "chema"
52 | version = "0.0.9"
53 | dependencies = [
54 | "combine",
55 | "env_logger",
56 | "lazy_static",
57 | "log",
58 | "regex",
59 | "serde",
60 | "serde_json",
61 | "serde_yaml",
62 | "structopt",
63 | "structopt-derive",
64 | ]
65 |
66 | [[package]]
67 | name = "clap"
68 | version = "2.33.3"
69 | source = "registry+https://github.com/rust-lang/crates.io-index"
70 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
71 | dependencies = [
72 | "ansi_term",
73 | "atty",
74 | "bitflags",
75 | "strsim",
76 | "textwrap",
77 | "unicode-width",
78 | "vec_map",
79 | ]
80 |
81 | [[package]]
82 | name = "combine"
83 | version = "4.3.2"
84 | source = "registry+https://github.com/rust-lang/crates.io-index"
85 | checksum = "2809f67365382d65fd2b6d9c22577231b954ed27400efeafbe687bda75abcc0b"
86 | dependencies = [
87 | "bytes",
88 | "memchr",
89 | "pin-project-lite",
90 | ]
91 |
92 | [[package]]
93 | name = "dtoa"
94 | version = "0.4.6"
95 | source = "registry+https://github.com/rust-lang/crates.io-index"
96 | checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
97 |
98 | [[package]]
99 | name = "env_logger"
100 | version = "0.6.2"
101 | source = "registry+https://github.com/rust-lang/crates.io-index"
102 | checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
103 | dependencies = [
104 | "atty",
105 | "humantime",
106 | "log",
107 | "regex",
108 | "termcolor",
109 | ]
110 |
111 | [[package]]
112 | name = "heck"
113 | version = "0.3.1"
114 | source = "registry+https://github.com/rust-lang/crates.io-index"
115 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
116 | dependencies = [
117 | "unicode-segmentation",
118 | ]
119 |
120 | [[package]]
121 | name = "hermit-abi"
122 | version = "0.1.17"
123 | source = "registry+https://github.com/rust-lang/crates.io-index"
124 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
125 | dependencies = [
126 | "libc",
127 | ]
128 |
129 | [[package]]
130 | name = "humantime"
131 | version = "1.3.0"
132 | source = "registry+https://github.com/rust-lang/crates.io-index"
133 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
134 | dependencies = [
135 | "quick-error",
136 | ]
137 |
138 | [[package]]
139 | name = "itoa"
140 | version = "0.4.6"
141 | source = "registry+https://github.com/rust-lang/crates.io-index"
142 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
143 |
144 | [[package]]
145 | name = "lazy_static"
146 | version = "1.4.0"
147 | source = "registry+https://github.com/rust-lang/crates.io-index"
148 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
149 |
150 | [[package]]
151 | name = "libc"
152 | version = "0.2.80"
153 | source = "registry+https://github.com/rust-lang/crates.io-index"
154 | checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
155 |
156 | [[package]]
157 | name = "linked-hash-map"
158 | version = "0.5.3"
159 | source = "registry+https://github.com/rust-lang/crates.io-index"
160 | checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
161 |
162 | [[package]]
163 | name = "log"
164 | version = "0.4.11"
165 | source = "registry+https://github.com/rust-lang/crates.io-index"
166 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
167 | dependencies = [
168 | "cfg-if",
169 | ]
170 |
171 | [[package]]
172 | name = "memchr"
173 | version = "2.3.4"
174 | source = "registry+https://github.com/rust-lang/crates.io-index"
175 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
176 |
177 | [[package]]
178 | name = "pin-project-lite"
179 | version = "0.1.11"
180 | source = "registry+https://github.com/rust-lang/crates.io-index"
181 | checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
182 |
183 | [[package]]
184 | name = "proc-macro2"
185 | version = "0.4.30"
186 | source = "registry+https://github.com/rust-lang/crates.io-index"
187 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
188 | dependencies = [
189 | "unicode-xid",
190 | ]
191 |
192 | [[package]]
193 | name = "quick-error"
194 | version = "1.2.3"
195 | source = "registry+https://github.com/rust-lang/crates.io-index"
196 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
197 |
198 | [[package]]
199 | name = "quote"
200 | version = "0.6.13"
201 | source = "registry+https://github.com/rust-lang/crates.io-index"
202 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
203 | dependencies = [
204 | "proc-macro2",
205 | ]
206 |
207 | [[package]]
208 | name = "regex"
209 | version = "1.4.2"
210 | source = "registry+https://github.com/rust-lang/crates.io-index"
211 | checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
212 | dependencies = [
213 | "aho-corasick",
214 | "memchr",
215 | "regex-syntax",
216 | "thread_local",
217 | ]
218 |
219 | [[package]]
220 | name = "regex-syntax"
221 | version = "0.6.21"
222 | source = "registry+https://github.com/rust-lang/crates.io-index"
223 | checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
224 |
225 | [[package]]
226 | name = "ryu"
227 | version = "1.0.5"
228 | source = "registry+https://github.com/rust-lang/crates.io-index"
229 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
230 |
231 | [[package]]
232 | name = "serde"
233 | version = "1.0.117"
234 | source = "registry+https://github.com/rust-lang/crates.io-index"
235 | checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
236 |
237 | [[package]]
238 | name = "serde_json"
239 | version = "1.0.59"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
242 | dependencies = [
243 | "itoa",
244 | "ryu",
245 | "serde",
246 | ]
247 |
248 | [[package]]
249 | name = "serde_yaml"
250 | version = "0.8.14"
251 | source = "registry+https://github.com/rust-lang/crates.io-index"
252 | checksum = "f7baae0a99f1a324984bcdc5f0718384c1f69775f1c7eec8b859b71b443e3fd7"
253 | dependencies = [
254 | "dtoa",
255 | "linked-hash-map",
256 | "serde",
257 | "yaml-rust",
258 | ]
259 |
260 | [[package]]
261 | name = "strsim"
262 | version = "0.8.0"
263 | source = "registry+https://github.com/rust-lang/crates.io-index"
264 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
265 |
266 | [[package]]
267 | name = "structopt"
268 | version = "0.2.18"
269 | source = "registry+https://github.com/rust-lang/crates.io-index"
270 | checksum = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7"
271 | dependencies = [
272 | "clap",
273 | "structopt-derive",
274 | ]
275 |
276 | [[package]]
277 | name = "structopt-derive"
278 | version = "0.2.18"
279 | source = "registry+https://github.com/rust-lang/crates.io-index"
280 | checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107"
281 | dependencies = [
282 | "heck",
283 | "proc-macro2",
284 | "quote",
285 | "syn",
286 | ]
287 |
288 | [[package]]
289 | name = "syn"
290 | version = "0.15.44"
291 | source = "registry+https://github.com/rust-lang/crates.io-index"
292 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
293 | dependencies = [
294 | "proc-macro2",
295 | "quote",
296 | "unicode-xid",
297 | ]
298 |
299 | [[package]]
300 | name = "termcolor"
301 | version = "1.1.0"
302 | source = "registry+https://github.com/rust-lang/crates.io-index"
303 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
304 | dependencies = [
305 | "winapi-util",
306 | ]
307 |
308 | [[package]]
309 | name = "textwrap"
310 | version = "0.11.0"
311 | source = "registry+https://github.com/rust-lang/crates.io-index"
312 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
313 | dependencies = [
314 | "unicode-width",
315 | ]
316 |
317 | [[package]]
318 | name = "thread_local"
319 | version = "1.0.1"
320 | source = "registry+https://github.com/rust-lang/crates.io-index"
321 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
322 | dependencies = [
323 | "lazy_static",
324 | ]
325 |
326 | [[package]]
327 | name = "unicode-segmentation"
328 | version = "1.6.0"
329 | source = "registry+https://github.com/rust-lang/crates.io-index"
330 | checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
331 |
332 | [[package]]
333 | name = "unicode-width"
334 | version = "0.1.8"
335 | source = "registry+https://github.com/rust-lang/crates.io-index"
336 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
337 |
338 | [[package]]
339 | name = "unicode-xid"
340 | version = "0.1.0"
341 | source = "registry+https://github.com/rust-lang/crates.io-index"
342 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
343 |
344 | [[package]]
345 | name = "vec_map"
346 | version = "0.8.2"
347 | source = "registry+https://github.com/rust-lang/crates.io-index"
348 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
349 |
350 | [[package]]
351 | name = "winapi"
352 | version = "0.3.9"
353 | source = "registry+https://github.com/rust-lang/crates.io-index"
354 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
355 | dependencies = [
356 | "winapi-i686-pc-windows-gnu",
357 | "winapi-x86_64-pc-windows-gnu",
358 | ]
359 |
360 | [[package]]
361 | name = "winapi-i686-pc-windows-gnu"
362 | version = "0.4.0"
363 | source = "registry+https://github.com/rust-lang/crates.io-index"
364 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
365 |
366 | [[package]]
367 | name = "winapi-util"
368 | version = "0.1.5"
369 | source = "registry+https://github.com/rust-lang/crates.io-index"
370 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
371 | dependencies = [
372 | "winapi",
373 | ]
374 |
375 | [[package]]
376 | name = "winapi-x86_64-pc-windows-gnu"
377 | version = "0.4.0"
378 | source = "registry+https://github.com/rust-lang/crates.io-index"
379 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
380 |
381 | [[package]]
382 | name = "yaml-rust"
383 | version = "0.4.4"
384 | source = "registry+https://github.com/rust-lang/crates.io-index"
385 | checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
386 | dependencies = [
387 | "linked-hash-map",
388 | ]
389 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors = ["Sunrin SHIMURA (keen) <3han5chou7@gmail.com>"]
3 | name = "chema"
4 | version = "0.0.9"
5 | license = "Apache-2.0/MIT"
6 | description = "An external DSL for JSON Schema"
7 | readme = "README.md"
8 | repository = "https://github.com/KeenS/chema"
9 | keywords = ["json-schema", "swagger", "DSL", "cli"]
10 | categories = ["development-tools"]
11 | edition="2018"
12 |
13 | [dependencies]
14 | combine = "4"
15 | env_logger = "0.6.0"
16 | lazy_static = "1.0"
17 | log = "0.4.0"
18 | regex = "1.0"
19 | serde = "1.0"
20 | serde_json = "1.0"
21 | serde_yaml = "0.8.0"
22 | structopt = "0.2.0"
23 | structopt-derive = "0.2.0"
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache 2.0
2 |
3 | Copyright 2017 κeen
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
17 |
18 | MIT
19 | Copyright 2017 κeen
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
22 |
23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
24 |
25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/KeenS/chema)
2 | [](https://ci.appveyor.com/project/KeenS/chema/branch/master)
3 |
4 | [](https://crates.io/crates/chema)
5 |
6 | # Chema
7 |
8 | Generate JSON Schema from a lightweight DSL.
9 |
10 | This is originally intended to generate a `definitions` section of swagger specifications.
11 |
12 | # Install
13 |
14 | Download a binary from https://github.com/KeenS/chema/releases
15 | or if you have setup `cargo`, use `cargo install like below.
16 |
17 | ```
18 | $ cargo install chema
19 | ```
20 |
21 | # Usage
22 |
23 | ```
24 | chema 0.0.8
25 | Sunrin SHIMURA (keen) <3han5chou7@gmail.com>
26 | An external DSL for JSON Schema
27 | USAGE:
28 | chema [FLAGS] [OPTIONS]
29 | FLAGS:
30 | -h, --help Prints help information
31 | --no-swagger don't use swagger specific notation
32 | --pack if pack the output
33 | -V, --version Prints version information
34 | OPTIONS:
35 | --format output format (json|yaml) [default: json]
36 | --path-prefix path prefix of paths [default: /definitions]
37 | ARGS:
38 | input file
39 | ```
40 |
41 | # Syntax
42 |
43 | ```
44 | TOP = ITEMS
45 | ITEMS = ITEM+
46 | ITEM = TYPEDEF
47 |
48 | TYPEDEF = "type" IDENT "=" TYPE ";"
49 |
50 | TYPE = "null" | "boolean" | "object" | "number" | "string" | "integer"
51 | | IDENT | "[" TYPE "]" | STRUCT | ENUM | TYPE "?"
52 | | "format" "(" STRING ")" | "url" "(" STRING ")"
53 | | TYPE "&" TYPE | TYPE "|" TYPE
54 | | TYPE "where" PRED
55 | | "(" TYPE ")" | STRING
56 |
57 | STRUCT = "struct" "{" (FIELD ",")+ "}"
58 | FIELD = IDENT "?"? ":" TYPE
59 |
60 | ENUM = "enum" "{" (VARIANT",")+ "}"
61 | VARIANT = STRING
62 |
63 | PRED = UNUMBER "<=" "length" | "length" <= UNUMBER
64 | | "format" "=" STRING | "it" "=~" REGEX
65 | | PRED && PRED
66 |
67 | IDENT = [a-zA-Z_][a-zA-Z0-9_]*
68 | STRIING = "\"" ([^"\\]|\\.)* "\""
69 | REGEX = "/" ([^/\\]|\\.)* "/"
70 | UNUMBER = [0-9]+
71 |
72 | COMMENT = "//" any "\n" | "/*" any "*/"
73 | DOC_COMMENT = "/**" any "*/"
74 | ```
75 |
76 | # Example
77 |
78 | See [etc](etc). `*.jsd`s are the sources and `*.jsons` are the generated files.
79 |
80 | # Supported Platforms
81 |
82 | UNIX-like system will be supported.
83 | Ubuntu LTS is the major target.
84 | Windows support is best effort and may not work .
85 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Based on the "trust" template v0.1.2
2 | # https://github.com/japaric/trust/tree/v0.1.2
3 |
4 | environment:
5 | global:
6 | # TODO This is the Rust channel that build jobs will use by default but can be
7 | # overridden on a case by case basis down below
8 | RUST_VERSION: stable
9 |
10 | # TODO Update this to match the name of your project.
11 | CRATE_NAME: chema
12 |
13 | # TODO These are all the build jobs. Adjust as necessary. Comment out what you
14 | # don't need
15 | matrix:
16 | # MinGW
17 | - TARGET: i686-pc-windows-gnu
18 | - TARGET: x86_64-pc-windows-gnu
19 |
20 | # MSVC
21 | - TARGET: i686-pc-windows-msvc
22 | - TARGET: x86_64-pc-windows-msvc
23 |
24 | # Testing other channels
25 | - TARGET: x86_64-pc-windows-gnu
26 | RUST_VERSION: nightly
27 | - TARGET: x86_64-pc-windows-msvc
28 | RUST_VERSION: nightly
29 |
30 | install:
31 | - ps: >-
32 | If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
33 | $Env:PATH += ';C:\msys64\mingw64\bin'
34 | } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
35 | $Env:PATH += ';C:\msys64\mingw32\bin'
36 | }
37 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/
38 | - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
39 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
40 | - rustc -Vv
41 | - cargo -V
42 |
43 | # TODO This is the "test phase", tweak it as you see fit
44 | test_script:
45 | # we don't run the "test phase" when doing deploys
46 | - if [%APPVEYOR_REPO_TAG%]==[false] (
47 | cargo build --target %TARGET% &&
48 | cargo test --target %TARGET% &&
49 | cargo run --target %TARGET% etc\example.jsd
50 | )
51 |
52 | before_deploy:
53 | # TODO Update this to build the artifacts that matter to you
54 | - cargo build --target %TARGET% --release
55 | - ps: ci\before_deploy.ps1
56 |
57 | deploy:
58 | artifact: /.*\.zip/
59 | # TODO update `auth_token.secure`
60 | # - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
61 | # - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
62 | # - Paste the output down here
63 | auth_token:
64 | secure: lTR5YHLdbEBUFRTU1M1l6uIf9ckmTsXhDP3vRMt19aVgtBZ08LfHWBfSaaPngAVR
65 | description: ''
66 | on:
67 | # TODO Here you can pick which targets will generate binary releases
68 | # In this example, there are some targets that are tested using the stable
69 | # and nightly channels. This condition makes sure there is only one release
70 | # for such targets and that's generated using the stable channel
71 | RUST_VERSION: stable
72 | appveyor_repo_tag: true
73 | provider: GitHub
74 |
75 | cache:
76 | - C:\Users\appveyor\.cargo\registry
77 | - target
78 |
79 | branches:
80 | only:
81 | # Release tags
82 | - /^v\d+\.\d+\.\d+.*$/
83 | - master
84 |
85 | notifications:
86 | - provider: Email
87 | on_build_success: false
88 |
89 | # Building is done in the test phase, so we disable Appveyor's build phase.
90 | build: false
91 |
--------------------------------------------------------------------------------
/ci/before_deploy.ps1:
--------------------------------------------------------------------------------
1 | # This script takes care of packaging the build artifacts that will go in the
2 | # release zipfile
3 |
4 | $SRC_DIR = $PWD.Path
5 | $STAGE = [System.Guid]::NewGuid().ToString()
6 |
7 | Set-Location $ENV:Temp
8 | New-Item -Type Directory -Name $STAGE
9 | Set-Location $STAGE
10 |
11 | $ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
12 |
13 | # TODO Update this to package the right artifacts
14 | Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\chema.exe" '.\'
15 |
16 | 7z a "$ZIP" *
17 |
18 | Push-AppveyorArtifact "$ZIP"
19 |
20 | Remove-Item *.* -Force
21 | Set-Location ..
22 | Remove-Item $STAGE
23 | Set-Location $SRC_DIR
24 |
--------------------------------------------------------------------------------
/ci/before_deploy.sh:
--------------------------------------------------------------------------------
1 | # This script takes care of building your crate and packaging it for release
2 |
3 | set -ex
4 |
5 | main() {
6 | local src=$(pwd) \
7 | stage=
8 |
9 | case $TRAVIS_OS_NAME in
10 | linux)
11 | stage=$(mktemp -d)
12 | ;;
13 | osx)
14 | stage=$(mktemp -d -t tmp)
15 | ;;
16 | esac
17 |
18 | test -f Cargo.lock || cargo generate-lockfile
19 |
20 | # TODO Update this to build the artifacts that matter to you
21 | cross build --target $TARGET --release
22 |
23 | # TODO Update this to package the right artifacts
24 | cp target/$TARGET/release/chema $stage/
25 |
26 | cd $stage
27 | tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
28 | cd $src
29 |
30 | rm -rf $stage
31 | }
32 |
33 | main
34 |
--------------------------------------------------------------------------------
/ci/install.sh:
--------------------------------------------------------------------------------
1 | set -ex
2 |
3 | main() {
4 | local target=
5 | if [ $TRAVIS_OS_NAME = linux ]; then
6 | target=x86_64-unknown-linux-musl
7 | sort=sort
8 | else
9 | target=x86_64-apple-darwin
10 | sort=gsort # for `sort --sort-version`, from brew's coreutils.
11 | fi
12 |
13 | # Builds for iOS are done on OSX, but require the specific target to be
14 | # installed.
15 | case $TARGET in
16 | aarch64-apple-ios)
17 | rustup target install aarch64-apple-ios
18 | ;;
19 | armv7-apple-ios)
20 | rustup target install armv7-apple-ios
21 | ;;
22 | armv7s-apple-ios)
23 | rustup target install armv7s-apple-ios
24 | ;;
25 | i386-apple-ios)
26 | rustup target install i386-apple-ios
27 | ;;
28 | x86_64-apple-ios)
29 | rustup target install x86_64-apple-ios
30 | ;;
31 | esac
32 |
33 | # This fetches latest stable release
34 | local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
35 | | cut -d/ -f3 \
36 | | grep -E '^v[0.1.0-9.]+$' \
37 | | $sort --version-sort \
38 | | tail -n1)
39 | curl -LSfs https://japaric.github.io/trust/install.sh | \
40 | sh -s -- \
41 | --force \
42 | --git japaric/cross \
43 | --tag $tag \
44 | --target $target
45 | }
46 |
47 | main
48 |
--------------------------------------------------------------------------------
/ci/script.sh:
--------------------------------------------------------------------------------
1 | # This script takes care of testing your crate
2 |
3 | set -ex
4 |
5 | # TODO This is the "test phase", tweak it as you see fit
6 | main() {
7 | cross build --target $TARGET
8 | # cross build --target $TARGET --release
9 |
10 | if [ ! -z $DISABLE_TESTS ]; then
11 | return
12 | fi
13 |
14 | cross test --target $TARGET
15 | # cross test --target $TARGET --release
16 |
17 | cross run --target $TARGET etc/example.jsd
18 | # cross run --target $TARGET --release
19 | }
20 |
21 | # we don't run the "test phase" when doing deploys
22 | if [ -z $TRAVIS_TAG ]; then
23 | main
24 | fi
25 |
--------------------------------------------------------------------------------
/etc/example.jsd:
--------------------------------------------------------------------------------
1 | /** id type */
2 | type id = integer;
3 |
4 | /** rotation angle */
5 | type angle = integer where 0<= it && it < 360 && it = 90 * n;
6 |
7 | /** @title User */
8 | type user = struct {
9 | /** unique id of the user */
10 | id: id,
11 | name: string?,
12 | type: enum {"admin", "writer", "reader"},
13 | SNSs: [string],
14 | };
15 | /**
16 | * @title Group
17 | * this expresses a group of users
18 | */
19 | type group = struct {
20 | id: id,
21 | admin: user?,
22 | members: [user],
23 | // this is short hand of `string where format = "date-time"`
24 | created_at: format("date-time"),
25 | };
26 |
27 | type password = string where 1 <= length && length <= 128 && it =~ /[a-z0-9!"#$%&'()=~|@]+/;
28 |
29 | type error = struct {
30 | code: string,
31 | message?: string,
32 | };
33 |
34 | type not_found = error & struct {
35 | code: "not_found",
36 | };
37 |
--------------------------------------------------------------------------------
/etc/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "angle": {
3 | "description": "rotation angle",
4 | "exclusiveMaximum": 360,
5 | "minimum": 0,
6 | "multipleOf": 90,
7 | "type": "integer"
8 | },
9 | "error": {
10 | "properties": {
11 | "code": {
12 | "type": "string"
13 | },
14 | "message": {
15 | "type": "string"
16 | }
17 | },
18 | "required": [
19 | "code"
20 | ],
21 | "type": "object"
22 | },
23 | "group": {
24 | "description": "this expresses a group of users",
25 | "properties": {
26 | "admin": {
27 | "anyOf": [
28 | {
29 | "$ref": "#/definitions/user"
30 | }
31 | ],
32 | "nullable": true
33 | },
34 | "created_at": {
35 | "format": "date-time",
36 | "type": "string"
37 | },
38 | "id": {
39 | "$ref": "#/definitions/id"
40 | },
41 | "members": {
42 | "items": {
43 | "$ref": "#/definitions/user"
44 | },
45 | "type": "array"
46 | }
47 | },
48 | "required": [
49 | "id",
50 | "admin",
51 | "members",
52 | "created_at"
53 | ],
54 | "title": "Group",
55 | "type": "object"
56 | },
57 | "id": {
58 | "description": "id type",
59 | "type": "integer"
60 | },
61 | "not_found": {
62 | "allOf": [
63 | {
64 | "$ref": "#/definitions/error"
65 | },
66 | {
67 | "properties": {
68 | "code": {
69 | "constant": "not_found"
70 | }
71 | },
72 | "required": [
73 | "code"
74 | ],
75 | "type": "object"
76 | }
77 | ]
78 | },
79 | "password": {
80 | "maxLength": 128,
81 | "minLength": 1,
82 | "pattern": "[a-z0-9!\"#$%&'()=~|@]+",
83 | "type": "string"
84 | },
85 | "user": {
86 | "properties": {
87 | "SNSs": {
88 | "items": {
89 | "type": "string"
90 | },
91 | "type": "array"
92 | },
93 | "id": {
94 | "$ref": "#/definitions/id",
95 | "description": "unique id of the user"
96 | },
97 | "name": {
98 | "nullable": true,
99 | "type": "string"
100 | },
101 | "type": {
102 | "enum": [
103 | "admin",
104 | "writer",
105 | "reader"
106 | ],
107 | "type": "string"
108 | }
109 | },
110 | "required": [
111 | "id",
112 | "name",
113 | "type",
114 | "SNSs"
115 | ],
116 | "title": "User",
117 | "type": "object"
118 | }
119 | }
--------------------------------------------------------------------------------
/src/compiler.rs:
--------------------------------------------------------------------------------
1 | use crate::parser::*;
2 | use crate::Config;
3 |
4 | use serde_json::{json, Map, Value};
5 |
6 | fn insert_if(mut map: Map, k: &str, v: Option) -> Map {
7 | if let Some(v) = v {
8 | map.insert(k.into(), Value::String(v));
9 | }
10 | map
11 | }
12 |
13 | pub fn compile(config: &Config, ast: AST) -> Map {
14 | ast.0
15 | .into_iter()
16 | .map(|Item::TypeDef(td)| {
17 | let type_ = compile_type(config, td.t.type_);
18 | let type_ = insert_if(type_, "description", td.meta.doc);
19 | let type_ = insert_if(type_, "title", td.meta.title);
20 | (td.t.ident.0, Value::Object(type_))
21 | })
22 | .collect()
23 | }
24 |
25 | fn compile_type(config: &Config, ty: Type) -> Map {
26 | use self::Type::*;
27 | let kvs = match ty {
28 | Null => vec![("type".to_string(), Value::String("null".into()))],
29 | Boolean => vec![("type".to_string(), Value::String("boolean".into()))],
30 | Object => vec![("type".to_string(), Value::String("object".into()))],
31 | Number => vec![("type".to_string(), Value::String("number".into()))],
32 | String => vec![("type".to_string(), Value::String("string".into()))],
33 | Integer => vec![("type".to_string(), Value::String("integer".into()))],
34 | Ref(url) => vec![("$ref".to_string(), Value::String(url))],
35 | Ident(crate::parser::Ident(i)) => vec![(
36 | "$ref".to_string(),
37 | Value::String(format!("#{}/{}", &config.path_prefix, i)),
38 | )],
39 | Const(c) => {
40 | use crate::parser::Const::*;
41 | match c {
42 | String(s) => vec![("constant".to_string(), Value::String(s))],
43 | }
44 | }
45 | Array(ty) => vec![
46 | ("type".to_string(), Value::String("array".into())),
47 | (
48 | "items".to_string(),
49 | Value::Object(compile_type(config, *ty)),
50 | ),
51 | ],
52 | Struct(Annot {
53 | t: crate::parser::Struct { fields },
54 | meta,
55 | }) => {
56 | let required = collect_requied(&fields)
57 | .into_iter()
58 | .map(|id| Value::String(id.0))
59 | .collect();
60 | let properties = fields
61 | .into_iter()
62 | .map(|f| {
63 | (
64 | f.t.ident.0,
65 | Value::Object(insert_if(
66 | compile_type(config, f.t.type_),
67 | "description",
68 | f.meta.doc,
69 | )),
70 | )
71 | })
72 | .collect();
73 | let mut vec = vec![
74 | ("type".to_string(), Value::String("object".to_string())),
75 | ("properties".to_string(), Value::Object(properties)),
76 | ("required".to_string(), Value::Array(required)),
77 | ];
78 | if let Some(title) = meta.title {
79 | vec.push(("title".to_string(), Value::String(title)));
80 | }
81 | if let Some(doc) = meta.doc {
82 | vec.push(("description".to_string(), Value::String(doc)))
83 | }
84 |
85 | vec
86 | }
87 | Enum(Annot {
88 | t: crate::parser::Enum { variants },
89 | meta,
90 | }) => {
91 | let variants = variants.into_iter().map(|v| Value::String(v.0)).collect();
92 | let mut vec = vec![
93 | ("type".to_string(), Value::String("string".into())),
94 | ("enum".to_string(), Value::Array(variants)),
95 | ];
96 | if let Some(title) = meta.title {
97 | vec.push(("title".to_string(), Value::String(title)));
98 | }
99 | if let Some(doc) = meta.doc {
100 | vec.push(("description".to_string(), Value::String(doc)))
101 | }
102 | vec
103 | }
104 | Option(ty) => {
105 | if config.no_swagger {
106 | let map = compile_type(config, *ty);
107 | let null = compile_type(config, Type::Null);
108 | vec![("oneOf".into(), Value::Array(vec![map.into(), null.into()]))]
109 | } else {
110 | let mut map = if matches!(&*ty, Ident(_) | Ref(_)) {
111 | // See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-580103688
112 | vec![("anyOf".to_string(), json!([compile_type(config, *ty)]))]
113 | .into_iter()
114 | .collect::