~repos /tide-jsx

#rust#proc-macro#jsx

git clone https://pyrossh.dev/repos/tide-jsx.git

Tide + JSX


cc58dd15 Gal Schlezinger

6 years ago
initial implementation
.github/workflows/test.yml ADDED
@@ -0,0 +1,35 @@
1
+ name: Test
2
+ on: [push, pull_request]
3
+ jobs:
4
+ format:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - uses: actions-rs/toolchain@v1
8
+ with:
9
+ toolchain: stable
10
+ - uses: actions/checkout@master
11
+ - run: rustup component add rustfmt
12
+ - run: cargo fmt --all -- --check
13
+ test:
14
+ runs-on: ${{ matrix.os }}
15
+ continue-on-error: ${{ matrix.experimental }}
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ os: [ubuntu-latest, windows-latest, macOS-latest]
20
+ rust: [stable]
21
+ experimental: [false]
22
+ include:
23
+ - rust: nightly
24
+ os: ubuntu-latest
25
+ experimental: true
26
+ steps:
27
+ - uses: actions-rs/toolchain@v1
28
+ with:
29
+ toolchain: ${{ matrix.rust }}
30
+ - uses: actions/checkout@master
31
+ - name: Run tests
32
+ run: |
33
+ cargo build --verbose
34
+ cargo test --verbose
35
+ cargo build --example basic
.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  target
2
2
  **/*.rs.bk
3
+ .DS_Store
Cargo.lock CHANGED
@@ -1,61 +1,1844 @@
1
1
  # This file is automatically @generated by Cargo.
2
2
  # It is not intended for manual editing.
3
+ version = 3
4
+
5
+ [[package]]
6
+ name = "aead"
7
+ version = "0.3.2"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331"
10
+ dependencies = [
11
+ "generic-array",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "aes"
16
+ version = "0.6.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
19
+ dependencies = [
20
+ "aes-soft",
21
+ "aesni",
22
+ "cipher",
23
+ ]
24
+
25
+ [[package]]
26
+ name = "aes-gcm"
27
+ version = "0.8.0"
28
+ source = "registry+https://github.com/rust-lang/crates.io-index"
29
+ checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da"
30
+ dependencies = [
31
+ "aead",
32
+ "aes",
33
+ "cipher",
34
+ "ctr",
35
+ "ghash",
36
+ "subtle",
37
+ ]
38
+
39
+ [[package]]
40
+ name = "aes-soft"
41
+ version = "0.6.4"
42
+ source = "registry+https://github.com/rust-lang/crates.io-index"
43
+ checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
44
+ dependencies = [
45
+ "cipher",
46
+ "opaque-debug",
47
+ ]
48
+
49
+ [[package]]
50
+ name = "aesni"
51
+ version = "0.10.0"
52
+ source = "registry+https://github.com/rust-lang/crates.io-index"
53
+ checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
54
+ dependencies = [
55
+ "cipher",
56
+ "opaque-debug",
57
+ ]
58
+
59
+ [[package]]
60
+ name = "android_system_properties"
61
+ version = "0.1.5"
62
+ source = "registry+https://github.com/rust-lang/crates.io-index"
63
+ checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
64
+ dependencies = [
65
+ "libc",
66
+ ]
67
+
68
+ [[package]]
69
+ name = "ansi_term"
70
+ version = "0.11.0"
71
+ source = "registry+https://github.com/rust-lang/crates.io-index"
72
+ checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
73
+ dependencies = [
74
+ "winapi",
75
+ ]
76
+
77
+ [[package]]
78
+ name = "anyhow"
79
+ version = "1.0.65"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
82
+
83
+ [[package]]
84
+ name = "arrayref"
85
+ version = "0.3.6"
86
+ source = "registry+https://github.com/rust-lang/crates.io-index"
87
+ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
88
+
89
+ [[package]]
90
+ name = "arrayvec"
91
+ version = "0.5.2"
92
+ source = "registry+https://github.com/rust-lang/crates.io-index"
93
+ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
94
+
95
+ [[package]]
96
+ name = "async-attributes"
97
+ version = "1.1.2"
98
+ source = "registry+https://github.com/rust-lang/crates.io-index"
99
+ checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
100
+ dependencies = [
101
+ "quote",
102
+ "syn",
103
+ ]
104
+
105
+ [[package]]
106
+ name = "async-channel"
107
+ version = "1.7.1"
108
+ source = "registry+https://github.com/rust-lang/crates.io-index"
109
+ checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
110
+ dependencies = [
111
+ "concurrent-queue",
112
+ "event-listener",
113
+ "futures-core",
114
+ ]
115
+
116
+ [[package]]
117
+ name = "async-dup"
118
+ version = "1.2.2"
119
+ source = "registry+https://github.com/rust-lang/crates.io-index"
120
+ checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c"
121
+ dependencies = [
122
+ "futures-io",
123
+ "simple-mutex",
124
+ ]
125
+
126
+ [[package]]
127
+ name = "async-executor"
128
+ version = "1.4.1"
129
+ source = "registry+https://github.com/rust-lang/crates.io-index"
130
+ checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
131
+ dependencies = [
132
+ "async-task",
133
+ "concurrent-queue",
134
+ "fastrand",
135
+ "futures-lite",
136
+ "once_cell",
137
+ "slab",
138
+ ]
139
+
140
+ [[package]]
141
+ name = "async-global-executor"
142
+ version = "2.3.0"
143
+ source = "registry+https://github.com/rust-lang/crates.io-index"
144
+ checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca"
145
+ dependencies = [
146
+ "async-channel",
147
+ "async-executor",
148
+ "async-io",
149
+ "async-lock",
150
+ "blocking",
151
+ "futures-lite",
152
+ "once_cell",
153
+ ]
154
+
155
+ [[package]]
156
+ name = "async-h1"
157
+ version = "2.3.3"
158
+ source = "registry+https://github.com/rust-lang/crates.io-index"
159
+ checksum = "8101020758a4fc3a7c326cb42aa99e9fa77cbfb76987c128ad956406fe1f70a7"
160
+ dependencies = [
161
+ "async-channel",
162
+ "async-dup",
163
+ "async-std",
164
+ "futures-core",
165
+ "http-types",
166
+ "httparse",
167
+ "log",
168
+ "pin-project",
169
+ ]
170
+
171
+ [[package]]
172
+ name = "async-io"
173
+ version = "1.9.0"
174
+ source = "registry+https://github.com/rust-lang/crates.io-index"
175
+ checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7"
176
+ dependencies = [
177
+ "autocfg",
178
+ "concurrent-queue",
179
+ "futures-lite",
180
+ "libc",
181
+ "log",
182
+ "once_cell",
183
+ "parking",
184
+ "polling",
185
+ "slab",
186
+ "socket2",
187
+ "waker-fn",
188
+ "winapi",
189
+ ]
190
+
191
+ [[package]]
192
+ name = "async-lock"
193
+ version = "2.5.0"
194
+ source = "registry+https://github.com/rust-lang/crates.io-index"
195
+ checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
196
+ dependencies = [
197
+ "event-listener",
198
+ ]
199
+
200
+ [[package]]
201
+ name = "async-process"
202
+ version = "1.5.0"
203
+ source = "registry+https://github.com/rust-lang/crates.io-index"
204
+ checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c"
205
+ dependencies = [
206
+ "async-io",
207
+ "autocfg",
208
+ "blocking",
209
+ "cfg-if 1.0.0",
210
+ "event-listener",
211
+ "futures-lite",
212
+ "libc",
213
+ "once_cell",
214
+ "signal-hook",
215
+ "winapi",
216
+ ]
217
+
218
+ [[package]]
219
+ name = "async-session"
220
+ version = "2.0.1"
221
+ source = "registry+https://github.com/rust-lang/crates.io-index"
222
+ checksum = "345022a2eed092cd105cc1b26fd61c341e100bd5fcbbd792df4baf31c2cc631f"
223
+ dependencies = [
224
+ "anyhow",
225
+ "async-std",
226
+ "async-trait",
227
+ "base64 0.12.3",
228
+ "bincode",
229
+ "blake3",
230
+ "chrono",
231
+ "hmac 0.8.1",
232
+ "kv-log-macro",
233
+ "rand 0.7.3",
234
+ "serde",
235
+ "serde_json",
236
+ "sha2",
237
+ ]
238
+
239
+ [[package]]
240
+ name = "async-sse"
241
+ version = "4.1.0"
242
+ source = "registry+https://github.com/rust-lang/crates.io-index"
243
+ checksum = "53bba003996b8fd22245cd0c59b869ba764188ed435392cf2796d03b805ade10"
244
+ dependencies = [
245
+ "async-channel",
246
+ "async-std",
247
+ "http-types",
248
+ "log",
249
+ "memchr",
250
+ "pin-project-lite 0.1.12",
251
+ ]
252
+
253
+ [[package]]
254
+ name = "async-std"
255
+ version = "1.12.0"
256
+ source = "registry+https://github.com/rust-lang/crates.io-index"
257
+ checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
258
+ dependencies = [
259
+ "async-attributes",
260
+ "async-channel",
261
+ "async-global-executor",
262
+ "async-io",
263
+ "async-lock",
264
+ "async-process",
265
+ "crossbeam-utils",
266
+ "futures-channel",
267
+ "futures-core",
268
+ "futures-io",
269
+ "futures-lite",
270
+ "gloo-timers",
271
+ "kv-log-macro",
272
+ "log",
273
+ "memchr",
274
+ "once_cell",
275
+ "pin-project-lite 0.2.9",
276
+ "pin-utils",
277
+ "slab",
278
+ "wasm-bindgen-futures",
279
+ ]
280
+
281
+ [[package]]
282
+ name = "async-task"
283
+ version = "4.3.0"
284
+ source = "registry+https://github.com/rust-lang/crates.io-index"
285
+ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
286
+
287
+ [[package]]
288
+ name = "async-trait"
289
+ version = "0.1.57"
290
+ source = "registry+https://github.com/rust-lang/crates.io-index"
291
+ checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
292
+ dependencies = [
293
+ "proc-macro2",
294
+ "quote",
295
+ "syn",
296
+ ]
297
+
298
+ [[package]]
299
+ name = "atomic-waker"
300
+ version = "1.0.0"
301
+ source = "registry+https://github.com/rust-lang/crates.io-index"
302
+ checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
303
+
304
+ [[package]]
305
+ name = "autocfg"
306
+ version = "1.1.0"
307
+ source = "registry+https://github.com/rust-lang/crates.io-index"
308
+ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
309
+
310
+ [[package]]
311
+ name = "base-x"
312
+ version = "0.2.11"
313
+ source = "registry+https://github.com/rust-lang/crates.io-index"
314
+ checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
315
+
316
+ [[package]]
317
+ name = "base64"
318
+ version = "0.12.3"
319
+ source = "registry+https://github.com/rust-lang/crates.io-index"
320
+ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
321
+
322
+ [[package]]
323
+ name = "base64"
324
+ version = "0.13.0"
325
+ source = "registry+https://github.com/rust-lang/crates.io-index"
326
+ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
327
+
328
+ [[package]]
329
+ name = "bincode"
330
+ version = "1.3.3"
331
+ source = "registry+https://github.com/rust-lang/crates.io-index"
332
+ checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
333
+ dependencies = [
334
+ "serde",
335
+ ]
336
+
337
+ [[package]]
338
+ name = "blake3"
339
+ version = "0.3.8"
340
+ source = "registry+https://github.com/rust-lang/crates.io-index"
341
+ checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3"
342
+ dependencies = [
343
+ "arrayref",
344
+ "arrayvec",
345
+ "cc",
346
+ "cfg-if 0.1.10",
347
+ "constant_time_eq",
348
+ "crypto-mac 0.8.0",
349
+ "digest",
350
+ ]
351
+
352
+ [[package]]
353
+ name = "block-buffer"
354
+ version = "0.9.0"
355
+ source = "registry+https://github.com/rust-lang/crates.io-index"
356
+ checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
357
+ dependencies = [
358
+ "generic-array",
359
+ ]
360
+
361
+ [[package]]
362
+ name = "blocking"
363
+ version = "1.2.0"
364
+ source = "registry+https://github.com/rust-lang/crates.io-index"
365
+ checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc"
366
+ dependencies = [
367
+ "async-channel",
368
+ "async-task",
369
+ "atomic-waker",
370
+ "fastrand",
371
+ "futures-lite",
372
+ "once_cell",
373
+ ]
374
+
375
+ [[package]]
376
+ name = "bumpalo"
377
+ version = "3.11.0"
378
+ source = "registry+https://github.com/rust-lang/crates.io-index"
379
+ checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
380
+
381
+ [[package]]
382
+ name = "cache-padded"
383
+ version = "1.2.0"
384
+ source = "registry+https://github.com/rust-lang/crates.io-index"
385
+ checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
386
+
387
+ [[package]]
388
+ name = "cc"
389
+ version = "1.0.73"
390
+ source = "registry+https://github.com/rust-lang/crates.io-index"
391
+ checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
392
+
393
+ [[package]]
394
+ name = "cfg-if"
395
+ version = "0.1.10"
396
+ source = "registry+https://github.com/rust-lang/crates.io-index"
397
+ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
398
+
399
+ [[package]]
400
+ name = "cfg-if"
401
+ version = "1.0.0"
402
+ source = "registry+https://github.com/rust-lang/crates.io-index"
403
+ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
404
+
405
+ [[package]]
406
+ name = "chrono"
407
+ version = "0.4.22"
408
+ source = "registry+https://github.com/rust-lang/crates.io-index"
409
+ checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
410
+ dependencies = [
411
+ "iana-time-zone",
412
+ "js-sys",
413
+ "num-integer",
414
+ "num-traits",
415
+ "serde",
416
+ "time 0.1.44",
417
+ "wasm-bindgen",
418
+ "winapi",
419
+ ]
420
+
421
+ [[package]]
422
+ name = "cipher"
423
+ version = "0.2.5"
424
+ source = "registry+https://github.com/rust-lang/crates.io-index"
425
+ checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
426
+ dependencies = [
427
+ "generic-array",
428
+ ]
429
+
430
+ [[package]]
431
+ name = "concurrent-queue"
432
+ version = "1.2.4"
433
+ source = "registry+https://github.com/rust-lang/crates.io-index"
434
+ checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
435
+ dependencies = [
436
+ "cache-padded",
437
+ ]
438
+
439
+ [[package]]
440
+ name = "const_fn"
441
+ version = "0.4.9"
442
+ source = "registry+https://github.com/rust-lang/crates.io-index"
443
+ checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935"
444
+
445
+ [[package]]
446
+ name = "constant_time_eq"
447
+ version = "0.1.5"
448
+ source = "registry+https://github.com/rust-lang/crates.io-index"
449
+ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
450
+
451
+ [[package]]
452
+ name = "cookie"
453
+ version = "0.14.4"
454
+ source = "registry+https://github.com/rust-lang/crates.io-index"
455
+ checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
456
+ dependencies = [
457
+ "aes-gcm",
458
+ "base64 0.13.0",
459
+ "hkdf",
460
+ "hmac 0.10.1",
461
+ "percent-encoding",
462
+ "rand 0.8.5",
463
+ "sha2",
464
+ "time 0.2.27",
465
+ "version_check",
466
+ ]
467
+
468
+ [[package]]
469
+ name = "core-foundation-sys"
470
+ version = "0.8.3"
471
+ source = "registry+https://github.com/rust-lang/crates.io-index"
472
+ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
473
+
474
+ [[package]]
475
+ name = "cpufeatures"
476
+ version = "0.2.5"
477
+ source = "registry+https://github.com/rust-lang/crates.io-index"
478
+ checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
479
+ dependencies = [
480
+ "libc",
481
+ ]
482
+
483
+ [[package]]
484
+ name = "cpuid-bool"
485
+ version = "0.2.0"
486
+ source = "registry+https://github.com/rust-lang/crates.io-index"
487
+ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba"
488
+
489
+ [[package]]
490
+ name = "crossbeam-utils"
491
+ version = "0.8.11"
492
+ source = "registry+https://github.com/rust-lang/crates.io-index"
493
+ checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
494
+ dependencies = [
495
+ "cfg-if 1.0.0",
496
+ "once_cell",
497
+ ]
498
+
499
+ [[package]]
500
+ name = "crypto-mac"
501
+ version = "0.8.0"
502
+ source = "registry+https://github.com/rust-lang/crates.io-index"
503
+ checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
504
+ dependencies = [
505
+ "generic-array",
506
+ "subtle",
507
+ ]
508
+
509
+ [[package]]
510
+ name = "crypto-mac"
511
+ version = "0.10.1"
512
+ source = "registry+https://github.com/rust-lang/crates.io-index"
513
+ checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a"
514
+ dependencies = [
515
+ "generic-array",
516
+ "subtle",
517
+ ]
518
+
519
+ [[package]]
520
+ name = "ctor"
521
+ version = "0.1.15"
522
+ source = "registry+https://github.com/rust-lang/crates.io-index"
523
+ checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227"
524
+ dependencies = [
525
+ "quote",
526
+ "syn",
527
+ ]
528
+
529
+ [[package]]
530
+ name = "ctr"
531
+ version = "0.6.0"
532
+ source = "registry+https://github.com/rust-lang/crates.io-index"
533
+ checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f"
534
+ dependencies = [
535
+ "cipher",
536
+ ]
537
+
538
+ [[package]]
539
+ name = "difference"
540
+ version = "2.0.0"
541
+ source = "registry+https://github.com/rust-lang/crates.io-index"
542
+ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
543
+
544
+ [[package]]
545
+ name = "digest"
546
+ version = "0.9.0"
547
+ source = "registry+https://github.com/rust-lang/crates.io-index"
548
+ checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
549
+ dependencies = [
550
+ "generic-array",
551
+ ]
552
+
553
+ [[package]]
554
+ name = "discard"
555
+ version = "1.0.4"
556
+ source = "registry+https://github.com/rust-lang/crates.io-index"
557
+ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
558
+
559
+ [[package]]
560
+ name = "erased-serde"
561
+ version = "0.3.23"
562
+ source = "registry+https://github.com/rust-lang/crates.io-index"
563
+ checksum = "54558e0ba96fbe24280072642eceb9d7d442e32c7ec0ea9e7ecd7b4ea2cf4e11"
564
+ dependencies = [
565
+ "serde",
566
+ ]
567
+
568
+ [[package]]
569
+ name = "event-listener"
570
+ version = "2.5.3"
571
+ source = "registry+https://github.com/rust-lang/crates.io-index"
572
+ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
573
+
574
+ [[package]]
575
+ name = "fastrand"
576
+ version = "1.8.0"
577
+ source = "registry+https://github.com/rust-lang/crates.io-index"
578
+ checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
579
+ dependencies = [
580
+ "instant",
581
+ ]
582
+
583
+ [[package]]
584
+ name = "femme"
585
+ version = "2.2.1"
586
+ source = "registry+https://github.com/rust-lang/crates.io-index"
587
+ checksum = "cc04871e5ae3aa2952d552dae6b291b3099723bf779a8054281c1366a54613ef"
588
+ dependencies = [
589
+ "cfg-if 1.0.0",
590
+ "js-sys",
591
+ "log",
592
+ "serde",
593
+ "serde_derive",
594
+ "serde_json",
595
+ "wasm-bindgen",
596
+ "web-sys",
597
+ ]
598
+
599
+ [[package]]
600
+ name = "form_urlencoded"
601
+ version = "1.1.0"
602
+ source = "registry+https://github.com/rust-lang/crates.io-index"
603
+ checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
604
+ dependencies = [
605
+ "percent-encoding",
606
+ ]
607
+
608
+ [[package]]
609
+ name = "futures-channel"
610
+ version = "0.3.24"
611
+ source = "registry+https://github.com/rust-lang/crates.io-index"
612
+ checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
613
+ dependencies = [
614
+ "futures-core",
615
+ ]
616
+
617
+ [[package]]
618
+ name = "futures-core"
619
+ version = "0.3.24"
620
+ source = "registry+https://github.com/rust-lang/crates.io-index"
621
+ checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
622
+
623
+ [[package]]
624
+ name = "futures-io"
625
+ version = "0.3.24"
626
+ source = "registry+https://github.com/rust-lang/crates.io-index"
627
+ checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
628
+
629
+ [[package]]
630
+ name = "futures-lite"
631
+ version = "1.12.0"
632
+ source = "registry+https://github.com/rust-lang/crates.io-index"
633
+ checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
634
+ dependencies = [
635
+ "fastrand",
636
+ "futures-core",
637
+ "futures-io",
638
+ "memchr",
639
+ "parking",
640
+ "pin-project-lite 0.2.9",
641
+ "waker-fn",
642
+ ]
643
+
644
+ [[package]]
645
+ name = "futures-macro"
646
+ version = "0.3.24"
647
+ source = "registry+https://github.com/rust-lang/crates.io-index"
648
+ checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17"
649
+ dependencies = [
650
+ "proc-macro2",
651
+ "quote",
652
+ "syn",
653
+ ]
654
+
655
+ [[package]]
656
+ name = "futures-task"
657
+ version = "0.3.24"
658
+ source = "registry+https://github.com/rust-lang/crates.io-index"
659
+ checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
660
+
661
+ [[package]]
662
+ name = "futures-util"
663
+ version = "0.3.24"
664
+ source = "registry+https://github.com/rust-lang/crates.io-index"
665
+ checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
666
+ dependencies = [
667
+ "futures-core",
668
+ "futures-io",
669
+ "futures-macro",
670
+ "futures-task",
671
+ "memchr",
672
+ "pin-project-lite 0.2.9",
673
+ "pin-utils",
674
+ "slab",
675
+ ]
676
+
677
+ [[package]]
678
+ name = "generic-array"
679
+ version = "0.14.6"
680
+ source = "registry+https://github.com/rust-lang/crates.io-index"
681
+ checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
682
+ dependencies = [
683
+ "typenum",
684
+ "version_check",
685
+ ]
686
+
687
+ [[package]]
688
+ name = "getrandom"
689
+ version = "0.1.16"
690
+ source = "registry+https://github.com/rust-lang/crates.io-index"
691
+ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
692
+ dependencies = [
693
+ "cfg-if 1.0.0",
694
+ "libc",
695
+ "wasi 0.9.0+wasi-snapshot-preview1",
696
+ ]
697
+
698
+ [[package]]
699
+ name = "getrandom"
700
+ version = "0.2.7"
701
+ source = "registry+https://github.com/rust-lang/crates.io-index"
702
+ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
703
+ dependencies = [
704
+ "cfg-if 1.0.0",
705
+ "libc",
706
+ "wasi 0.11.0+wasi-snapshot-preview1",
707
+ ]
708
+
709
+ [[package]]
710
+ name = "ghash"
711
+ version = "0.3.1"
712
+ source = "registry+https://github.com/rust-lang/crates.io-index"
713
+ checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375"
714
+ dependencies = [
715
+ "opaque-debug",
716
+ "polyval",
717
+ ]
718
+
719
+ [[package]]
720
+ name = "glob"
721
+ version = "0.3.0"
722
+ source = "registry+https://github.com/rust-lang/crates.io-index"
723
+ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
724
+
725
+ [[package]]
726
+ name = "gloo-timers"
727
+ version = "0.2.4"
728
+ source = "registry+https://github.com/rust-lang/crates.io-index"
729
+ checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9"
730
+ dependencies = [
731
+ "futures-channel",
732
+ "futures-core",
733
+ "js-sys",
734
+ "wasm-bindgen",
735
+ ]
736
+
737
+ [[package]]
738
+ name = "hkdf"
739
+ version = "0.10.0"
740
+ source = "registry+https://github.com/rust-lang/crates.io-index"
741
+ checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f"
742
+ dependencies = [
743
+ "digest",
744
+ "hmac 0.10.1",
745
+ ]
746
+
747
+ [[package]]
748
+ name = "hmac"
749
+ version = "0.8.1"
750
+ source = "registry+https://github.com/rust-lang/crates.io-index"
751
+ checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
752
+ dependencies = [
753
+ "crypto-mac 0.8.0",
754
+ "digest",
755
+ ]
756
+
757
+ [[package]]
758
+ name = "hmac"
759
+ version = "0.10.1"
760
+ source = "registry+https://github.com/rust-lang/crates.io-index"
761
+ checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
762
+ dependencies = [
763
+ "crypto-mac 0.10.1",
764
+ "digest",
765
+ ]
766
+
767
+ [[package]]
768
+ name = "http-client"
769
+ version = "6.5.3"
770
+ source = "registry+https://github.com/rust-lang/crates.io-index"
771
+ checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5"
772
+ dependencies = [
773
+ "async-trait",
774
+ "cfg-if 1.0.0",
775
+ "http-types",
776
+ "log",
777
+ ]
778
+
779
+ [[package]]
780
+ name = "http-types"
781
+ version = "2.12.0"
782
+ source = "registry+https://github.com/rust-lang/crates.io-index"
783
+ checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
784
+ dependencies = [
785
+ "anyhow",
786
+ "async-channel",
787
+ "async-std",
788
+ "base64 0.13.0",
789
+ "cookie",
790
+ "futures-lite",
791
+ "infer",
792
+ "pin-project-lite 0.2.9",
793
+ "rand 0.7.3",
794
+ "serde",
795
+ "serde_json",
796
+ "serde_qs",
797
+ "serde_urlencoded",
798
+ "url",
799
+ ]
800
+
801
+ [[package]]
802
+ name = "httparse"
803
+ version = "1.8.0"
804
+ source = "registry+https://github.com/rust-lang/crates.io-index"
805
+ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
806
+
807
+ [[package]]
808
+ name = "iana-time-zone"
809
+ version = "0.1.48"
810
+ source = "registry+https://github.com/rust-lang/crates.io-index"
811
+ checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0"
812
+ dependencies = [
813
+ "android_system_properties",
814
+ "core-foundation-sys",
815
+ "js-sys",
816
+ "once_cell",
817
+ "wasm-bindgen",
818
+ "winapi",
819
+ ]
820
+
821
+ [[package]]
822
+ name = "idna"
823
+ version = "0.3.0"
824
+ source = "registry+https://github.com/rust-lang/crates.io-index"
825
+ checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
826
+ dependencies = [
827
+ "unicode-bidi",
828
+ "unicode-normalization",
829
+ ]
830
+
831
+ [[package]]
832
+ name = "infer"
833
+ version = "0.2.3"
834
+ source = "registry+https://github.com/rust-lang/crates.io-index"
835
+ checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
836
+
837
+ [[package]]
838
+ name = "instant"
839
+ version = "0.1.12"
840
+ source = "registry+https://github.com/rust-lang/crates.io-index"
841
+ checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
842
+ dependencies = [
843
+ "cfg-if 1.0.0",
844
+ ]
845
+
846
+ [[package]]
847
+ name = "itoa"
848
+ version = "1.0.3"
849
+ source = "registry+https://github.com/rust-lang/crates.io-index"
850
+ checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
851
+
852
+ [[package]]
853
+ name = "js-sys"
854
+ version = "0.3.60"
855
+ source = "registry+https://github.com/rust-lang/crates.io-index"
856
+ checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
857
+ dependencies = [
858
+ "wasm-bindgen",
859
+ ]
860
+
861
+ [[package]]
862
+ name = "kv-log-macro"
863
+ version = "1.0.7"
864
+ source = "registry+https://github.com/rust-lang/crates.io-index"
865
+ checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
866
+ dependencies = [
867
+ "log",
868
+ ]
869
+
870
+ [[package]]
871
+ name = "libc"
872
+ version = "0.2.132"
873
+ source = "registry+https://github.com/rust-lang/crates.io-index"
874
+ checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
875
+
876
+ [[package]]
877
+ name = "log"
878
+ version = "0.4.17"
879
+ source = "registry+https://github.com/rust-lang/crates.io-index"
880
+ checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
881
+ dependencies = [
882
+ "cfg-if 1.0.0",
883
+ "serde",
884
+ "value-bag",
885
+ ]
886
+
887
+ [[package]]
888
+ name = "memchr"
889
+ version = "2.5.0"
890
+ source = "registry+https://github.com/rust-lang/crates.io-index"
891
+ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
892
+
893
+ [[package]]
894
+ name = "mime"
895
+ version = "0.3.16"
896
+ source = "registry+https://github.com/rust-lang/crates.io-index"
897
+ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
898
+
899
+ [[package]]
900
+ name = "mime_guess"
901
+ version = "2.0.4"
902
+ source = "registry+https://github.com/rust-lang/crates.io-index"
903
+ checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
904
+ dependencies = [
905
+ "mime",
906
+ "unicase",
907
+ ]
908
+
909
+ [[package]]
910
+ name = "num-integer"
911
+ version = "0.1.45"
912
+ source = "registry+https://github.com/rust-lang/crates.io-index"
913
+ checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
914
+ dependencies = [
915
+ "autocfg",
916
+ "num-traits",
917
+ ]
918
+
919
+ [[package]]
920
+ name = "num-traits"
921
+ version = "0.2.15"
922
+ source = "registry+https://github.com/rust-lang/crates.io-index"
923
+ checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
924
+ dependencies = [
925
+ "autocfg",
926
+ ]
927
+
928
+ [[package]]
929
+ name = "once_cell"
930
+ version = "1.14.0"
931
+ source = "registry+https://github.com/rust-lang/crates.io-index"
932
+ checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
933
+
934
+ [[package]]
935
+ name = "opaque-debug"
936
+ version = "0.3.0"
937
+ source = "registry+https://github.com/rust-lang/crates.io-index"
938
+ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
939
+
940
+ [[package]]
941
+ name = "output_vt100"
942
+ version = "0.1.2"
943
+ source = "registry+https://github.com/rust-lang/crates.io-index"
944
+ checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
945
+ dependencies = [
946
+ "winapi",
947
+ ]
948
+
949
+ [[package]]
950
+ name = "parking"
951
+ version = "2.0.0"
952
+ source = "registry+https://github.com/rust-lang/crates.io-index"
953
+ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
954
+
955
+ [[package]]
956
+ name = "percent-encoding"
957
+ version = "2.2.0"
958
+ source = "registry+https://github.com/rust-lang/crates.io-index"
959
+ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
960
+
961
+ [[package]]
962
+ name = "pin-project"
963
+ version = "1.0.12"
964
+ source = "registry+https://github.com/rust-lang/crates.io-index"
965
+ checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
966
+ dependencies = [
967
+ "pin-project-internal",
968
+ ]
969
+
970
+ [[package]]
971
+ name = "pin-project-internal"
972
+ version = "1.0.12"
973
+ source = "registry+https://github.com/rust-lang/crates.io-index"
974
+ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
975
+ dependencies = [
976
+ "proc-macro2",
977
+ "quote",
978
+ "syn",
979
+ ]
980
+
981
+ [[package]]
982
+ name = "pin-project-lite"
983
+ version = "0.1.12"
984
+ source = "registry+https://github.com/rust-lang/crates.io-index"
985
+ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
986
+
987
+ [[package]]
988
+ name = "pin-project-lite"
989
+ version = "0.2.9"
990
+ source = "registry+https://github.com/rust-lang/crates.io-index"
991
+ checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
992
+
993
+ [[package]]
994
+ name = "pin-utils"
995
+ version = "0.1.0"
996
+ source = "registry+https://github.com/rust-lang/crates.io-index"
997
+ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
998
+
999
+ [[package]]
1000
+ name = "polling"
1001
+ version = "2.3.0"
1002
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1003
+ checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011"
1004
+ dependencies = [
1005
+ "autocfg",
1006
+ "cfg-if 1.0.0",
1007
+ "libc",
1008
+ "log",
1009
+ "wepoll-ffi",
1010
+ "winapi",
1011
+ ]
1012
+
1013
+ [[package]]
1014
+ name = "polyval"
1015
+ version = "0.4.5"
1016
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1017
+ checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd"
1018
+ dependencies = [
1019
+ "cpuid-bool",
1020
+ "opaque-debug",
1021
+ "universal-hash",
1022
+ ]
1023
+
1024
+ [[package]]
1025
+ name = "ppv-lite86"
1026
+ version = "0.2.16"
1027
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1028
+ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
1029
+
1030
+ [[package]]
1031
+ name = "pretty_assertions"
1032
+ version = "0.6.1"
1033
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1034
+ checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
1035
+ dependencies = [
1036
+ "ansi_term",
1037
+ "ctor",
1038
+ "difference",
1039
+ "output_vt100",
1040
+ ]
1041
+
1042
+ [[package]]
1043
+ name = "proc-macro-error"
1044
+ version = "1.0.3"
1045
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1046
+ checksum = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880"
1047
+ dependencies = [
1048
+ "proc-macro-error-attr",
1049
+ "proc-macro2",
1050
+ "quote",
1051
+ "syn",
1052
+ "version_check",
1053
+ ]
1054
+
1055
+ [[package]]
1056
+ name = "proc-macro-error-attr"
1057
+ version = "1.0.3"
1058
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1059
+ checksum = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50"
1060
+ dependencies = [
1061
+ "proc-macro2",
1062
+ "quote",
1063
+ "syn",
1064
+ "syn-mid",
1065
+ "version_check",
1066
+ ]
1067
+
1068
+ [[package]]
1069
+ name = "proc-macro-hack"
1070
+ version = "0.5.19"
1071
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1072
+ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
1073
+
1074
+ [[package]]
1075
+ name = "proc-macro2"
1076
+ version = "1.0.43"
1077
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1078
+ checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
1079
+ dependencies = [
1080
+ "unicode-ident",
1081
+ ]
1082
+
1083
+ [[package]]
1084
+ name = "quote"
1085
+ version = "1.0.7"
1086
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1087
+ checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
1088
+ dependencies = [
1089
+ "proc-macro2",
1090
+ ]
1091
+
1092
+ [[package]]
1093
+ name = "rand"
1094
+ version = "0.7.3"
1095
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1096
+ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
1097
+ dependencies = [
1098
+ "getrandom 0.1.16",
1099
+ "libc",
1100
+ "rand_chacha 0.2.2",
1101
+ "rand_core 0.5.1",
1102
+ "rand_hc",
1103
+ ]
1104
+
1105
+ [[package]]
1106
+ name = "rand"
1107
+ version = "0.8.5"
1108
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1109
+ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
1110
+ dependencies = [
1111
+ "libc",
1112
+ "rand_chacha 0.3.1",
1113
+ "rand_core 0.6.4",
1114
+ ]
1115
+
1116
+ [[package]]
1117
+ name = "rand_chacha"
1118
+ version = "0.2.2"
1119
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1120
+ checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
1121
+ dependencies = [
1122
+ "ppv-lite86",
1123
+ "rand_core 0.5.1",
1124
+ ]
1125
+
1126
+ [[package]]
1127
+ name = "rand_chacha"
1128
+ version = "0.3.1"
1129
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1130
+ checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
1131
+ dependencies = [
1132
+ "ppv-lite86",
1133
+ "rand_core 0.6.4",
1134
+ ]
1135
+
1136
+ [[package]]
1137
+ name = "rand_core"
1138
+ version = "0.5.1"
1139
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1140
+ checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
1141
+ dependencies = [
1142
+ "getrandom 0.1.16",
1143
+ ]
1144
+
1145
+ [[package]]
1146
+ name = "rand_core"
1147
+ version = "0.6.4"
1148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1149
+ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1150
+ dependencies = [
1151
+ "getrandom 0.2.7",
1152
+ ]
1153
+
1154
+ [[package]]
1155
+ name = "rand_hc"
1156
+ version = "0.2.0"
1157
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1158
+ checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
1159
+ dependencies = [
1160
+ "rand_core 0.5.1",
1161
+ ]
1162
+
1163
+ [[package]]
1164
+ name = "route-recognizer"
1165
+ version = "0.2.0"
1166
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1167
+ checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e"
1168
+
1169
+ [[package]]
1170
+ name = "rustc_version"
1171
+ version = "0.2.3"
1172
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1173
+ checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1174
+ dependencies = [
1175
+ "semver",
1176
+ ]
1177
+
1178
+ [[package]]
1179
+ name = "ryu"
1180
+ version = "1.0.11"
1181
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1182
+ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
1183
+
1184
+ [[package]]
1185
+ name = "semver"
1186
+ version = "0.9.0"
1187
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1188
+ checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1189
+ dependencies = [
1190
+ "semver-parser",
1191
+ ]
1192
+
1193
+ [[package]]
1194
+ name = "semver-parser"
1195
+ version = "0.7.0"
1196
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1197
+ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1198
+
1199
+ [[package]]
1200
+ name = "serde"
1201
+ version = "1.0.144"
1202
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1203
+ checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
1204
+ dependencies = [
1205
+ "serde_derive",
1206
+ ]
1207
+
1208
+ [[package]]
1209
+ name = "serde_derive"
1210
+ version = "1.0.144"
1211
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1212
+ checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
1213
+ dependencies = [
1214
+ "proc-macro2",
1215
+ "quote",
1216
+ "syn",
1217
+ ]
1218
+
3
1219
  [[package]]
4
- name = "proc-macro2"
1220
+ name = "serde_fmt"
5
- version = "1.0.3"
1221
+ version = "1.0.1"
6
1222
  source = "registry+https://github.com/rust-lang/crates.io-index"
1223
+ checksum = "2963a69a2b3918c1dc75a45a18bd3fcd1120e31d3f59deb1b2f9b5d5ffb8baa4"
7
1224
  dependencies = [
8
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1225
+ "serde",
9
1226
  ]
10
1227
 
11
1228
  [[package]]
12
- name = "quote"
1229
+ name = "serde_json"
13
- version = "1.0.2"
1230
+ version = "1.0.85"
14
1231
  source = "registry+https://github.com/rust-lang/crates.io-index"
1232
+ checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
15
1233
  dependencies = [
1234
+ "itoa",
1235
+ "ryu",
16
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
1236
+ "serde",
17
1237
  ]
18
1238
 
19
1239
  [[package]]
20
- name = "render"
1240
+ name = "serde_qs"
21
- version = "0.1.0"
1241
+ version = "0.8.5"
1242
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1243
+ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
22
1244
  dependencies = [
23
- "render_macros 0.1.0",
1245
+ "percent-encoding",
1246
+ "serde",
1247
+ "thiserror",
24
1248
  ]
25
1249
 
26
1250
  [[package]]
27
- name = "render_macros"
1251
+ name = "serde_urlencoded"
28
- version = "0.1.0"
1252
+ version = "0.7.1"
1253
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1254
+ checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
29
1255
  dependencies = [
30
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
31
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1256
+ "form_urlencoded",
1257
+ "itoa",
1258
+ "ryu",
32
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1259
+ "serde",
33
1260
  ]
34
1261
 
35
1262
  [[package]]
1263
+ name = "sha1"
1264
+ version = "0.6.1"
1265
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1266
+ checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
1267
+ dependencies = [
1268
+ "sha1_smol",
1269
+ ]
1270
+
1271
+ [[package]]
1272
+ name = "sha1_smol"
1273
+ version = "1.0.0"
1274
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1275
+ checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
1276
+
1277
+ [[package]]
1278
+ name = "sha2"
1279
+ version = "0.9.9"
1280
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1281
+ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
1282
+ dependencies = [
1283
+ "block-buffer",
1284
+ "cfg-if 1.0.0",
1285
+ "cpufeatures",
1286
+ "digest",
1287
+ "opaque-debug",
1288
+ ]
1289
+
1290
+ [[package]]
1291
+ name = "signal-hook"
1292
+ version = "0.3.14"
1293
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1294
+ checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
1295
+ dependencies = [
1296
+ "libc",
1297
+ "signal-hook-registry",
1298
+ ]
1299
+
1300
+ [[package]]
1301
+ name = "signal-hook-registry"
1302
+ version = "1.4.0"
1303
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1304
+ checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
1305
+ dependencies = [
1306
+ "libc",
1307
+ ]
1308
+
1309
+ [[package]]
1310
+ name = "simple-mutex"
1311
+ version = "1.1.5"
1312
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1313
+ checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6"
1314
+ dependencies = [
1315
+ "event-listener",
1316
+ ]
1317
+
1318
+ [[package]]
1319
+ name = "slab"
1320
+ version = "0.4.7"
1321
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1322
+ checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
1323
+ dependencies = [
1324
+ "autocfg",
1325
+ ]
1326
+
1327
+ [[package]]
1328
+ name = "socket2"
1329
+ version = "0.4.7"
1330
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1331
+ checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
1332
+ dependencies = [
1333
+ "libc",
1334
+ "winapi",
1335
+ ]
1336
+
1337
+ [[package]]
1338
+ name = "standback"
1339
+ version = "0.2.17"
1340
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1341
+ checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
1342
+ dependencies = [
1343
+ "version_check",
1344
+ ]
1345
+
1346
+ [[package]]
1347
+ name = "stdweb"
1348
+ version = "0.4.20"
1349
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1350
+ checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
1351
+ dependencies = [
1352
+ "discard",
1353
+ "rustc_version",
1354
+ "stdweb-derive",
1355
+ "stdweb-internal-macros",
1356
+ "stdweb-internal-runtime",
1357
+ "wasm-bindgen",
1358
+ ]
1359
+
1360
+ [[package]]
36
- name = "render_tests"
1361
+ name = "stdweb-derive"
1362
+ version = "0.5.3"
1363
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1364
+ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
1365
+ dependencies = [
1366
+ "proc-macro2",
1367
+ "quote",
1368
+ "serde",
1369
+ "serde_derive",
1370
+ "syn",
1371
+ ]
1372
+
1373
+ [[package]]
1374
+ name = "stdweb-internal-macros"
1375
+ version = "0.2.9"
1376
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1377
+ checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
1378
+ dependencies = [
1379
+ "base-x",
1380
+ "proc-macro2",
1381
+ "quote",
1382
+ "serde",
1383
+ "serde_derive",
1384
+ "serde_json",
1385
+ "sha1",
1386
+ "syn",
1387
+ ]
1388
+
1389
+ [[package]]
1390
+ name = "stdweb-internal-runtime"
37
- version = "0.1.0"
1391
+ version = "0.1.5"
1392
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1393
+ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
1394
+
1395
+ [[package]]
1396
+ name = "subtle"
1397
+ version = "2.4.1"
1398
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1399
+ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
1400
+
1401
+ [[package]]
1402
+ name = "surf"
1403
+ version = "2.3.2"
1404
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1405
+ checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7"
1406
+ dependencies = [
1407
+ "async-std",
1408
+ "async-trait",
1409
+ "cfg-if 1.0.0",
1410
+ "futures-util",
1411
+ "getrandom 0.2.7",
1412
+ "http-client",
1413
+ "http-types",
1414
+ "log",
1415
+ "mime_guess",
1416
+ "pin-project-lite 0.2.9",
1417
+ "serde",
1418
+ "serde_json",
1419
+ ]
1420
+
1421
+ [[package]]
1422
+ name = "sval"
1423
+ version = "1.0.0-alpha.5"
1424
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1425
+ checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08"
38
1426
  dependencies = [
39
- "render 0.1.0",
1427
+ "serde",
40
1428
  ]
41
1429
 
42
1430
  [[package]]
43
1431
  name = "syn"
44
- version = "1.0.5"
1432
+ version = "1.0.99"
45
1433
  source = "registry+https://github.com/rust-lang/crates.io-index"
1434
+ checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
46
1435
  dependencies = [
47
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
1436
+ "proc-macro2",
48
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1437
+ "quote",
49
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1438
+ "unicode-ident",
50
1439
  ]
51
1440
 
52
1441
  [[package]]
53
- name = "unicode-xid"
1442
+ name = "syn-mid"
54
- version = "0.2.0"
1443
+ version = "0.5.0"
1444
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1445
+ checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
1446
+ dependencies = [
1447
+ "proc-macro2",
1448
+ "quote",
1449
+ "syn",
1450
+ ]
1451
+
1452
+ [[package]]
1453
+ name = "termcolor"
1454
+ version = "1.1.3"
1455
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1456
+ checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
1457
+ dependencies = [
1458
+ "winapi-util",
1459
+ ]
1460
+
1461
+ [[package]]
1462
+ name = "thiserror"
1463
+ version = "1.0.35"
1464
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1465
+ checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85"
1466
+ dependencies = [
1467
+ "thiserror-impl",
1468
+ ]
1469
+
1470
+ [[package]]
1471
+ name = "thiserror-impl"
1472
+ version = "1.0.35"
1473
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1474
+ checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783"
1475
+ dependencies = [
1476
+ "proc-macro2",
1477
+ "quote",
1478
+ "syn",
1479
+ ]
1480
+
1481
+ [[package]]
1482
+ name = "tide"
1483
+ version = "0.16.0"
1484
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1485
+ checksum = "c459573f0dd2cc734b539047f57489ea875af8ee950860ded20cf93a79a1dee0"
1486
+ dependencies = [
1487
+ "async-h1",
1488
+ "async-session",
1489
+ "async-sse",
1490
+ "async-std",
1491
+ "async-trait",
1492
+ "femme",
1493
+ "futures-util",
1494
+ "http-client",
1495
+ "http-types",
1496
+ "kv-log-macro",
1497
+ "log",
1498
+ "pin-project-lite 0.2.9",
1499
+ "route-recognizer",
1500
+ "serde",
1501
+ "serde_json",
1502
+ ]
1503
+
1504
+ [[package]]
1505
+ name = "tide-jsx"
1506
+ version = "0.4.0"
1507
+ dependencies = [
1508
+ "async-std",
1509
+ "pretty_assertions",
1510
+ "tide",
1511
+ "tide-jsx-impl",
1512
+ "tide-testing",
1513
+ "trybuild",
1514
+ ]
1515
+
1516
+ [[package]]
1517
+ name = "tide-jsx-impl"
1518
+ version = "0.3.0"
1519
+ dependencies = [
1520
+ "proc-macro-error",
1521
+ "proc-macro2",
1522
+ "quote",
1523
+ "syn",
1524
+ ]
1525
+
1526
+ [[package]]
1527
+ name = "tide-testing"
1528
+ version = "0.1.3"
1529
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1530
+ checksum = "5a59ea33dec6d205e4173cf7825dcfc78600c1726d931132d99b38b932495111"
1531
+ dependencies = [
1532
+ "serde",
1533
+ "serde_json",
1534
+ "surf",
1535
+ "tide",
1536
+ ]
1537
+
1538
+ [[package]]
1539
+ name = "time"
1540
+ version = "0.1.44"
1541
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1542
+ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
1543
+ dependencies = [
1544
+ "libc",
1545
+ "wasi 0.10.0+wasi-snapshot-preview1",
1546
+ "winapi",
1547
+ ]
1548
+
1549
+ [[package]]
1550
+ name = "time"
1551
+ version = "0.2.27"
1552
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1553
+ checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
1554
+ dependencies = [
1555
+ "const_fn",
1556
+ "libc",
1557
+ "standback",
1558
+ "stdweb",
1559
+ "time-macros",
1560
+ "version_check",
1561
+ "winapi",
1562
+ ]
1563
+
1564
+ [[package]]
1565
+ name = "time-macros"
1566
+ version = "0.1.1"
55
1567
  source = "registry+https://github.com/rust-lang/crates.io-index"
1568
+ checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
1569
+ dependencies = [
1570
+ "proc-macro-hack",
1571
+ "time-macros-impl",
1572
+ ]
1573
+
1574
+ [[package]]
1575
+ name = "time-macros-impl"
1576
+ version = "0.1.2"
1577
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1578
+ checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
1579
+ dependencies = [
1580
+ "proc-macro-hack",
1581
+ "proc-macro2",
1582
+ "quote",
1583
+ "standback",
1584
+ "syn",
1585
+ ]
1586
+
1587
+ [[package]]
1588
+ name = "tinyvec"
1589
+ version = "1.6.0"
1590
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1591
+ checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
1592
+ dependencies = [
1593
+ "tinyvec_macros",
1594
+ ]
1595
+
1596
+ [[package]]
1597
+ name = "tinyvec_macros"
1598
+ version = "0.1.0"
1599
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1600
+ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
1601
+
1602
+ [[package]]
1603
+ name = "toml"
1604
+ version = "0.5.9"
1605
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1606
+ checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
1607
+ dependencies = [
1608
+ "serde",
1609
+ ]
1610
+
1611
+ [[package]]
1612
+ name = "trybuild"
1613
+ version = "1.0.64"
1614
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1615
+ checksum = "e7f408301c7480f9e6294eb779cfc907f54bd901a9660ef24d7f233ed5376485"
1616
+ dependencies = [
1617
+ "glob",
1618
+ "once_cell",
1619
+ "serde",
1620
+ "serde_derive",
1621
+ "serde_json",
1622
+ "termcolor",
1623
+ "toml",
1624
+ ]
1625
+
1626
+ [[package]]
1627
+ name = "typenum"
1628
+ version = "1.15.0"
1629
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1630
+ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
1631
+
1632
+ [[package]]
1633
+ name = "unicase"
1634
+ version = "2.6.0"
1635
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1636
+ checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1637
+ dependencies = [
1638
+ "version_check",
1639
+ ]
1640
+
1641
+ [[package]]
1642
+ name = "unicode-bidi"
1643
+ version = "0.3.8"
1644
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1645
+ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
1646
+
1647
+ [[package]]
1648
+ name = "unicode-ident"
1649
+ version = "1.0.4"
1650
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1651
+ checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
1652
+
1653
+ [[package]]
1654
+ name = "unicode-normalization"
1655
+ version = "0.1.22"
1656
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1657
+ checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
1658
+ dependencies = [
1659
+ "tinyvec",
1660
+ ]
1661
+
1662
+ [[package]]
1663
+ name = "universal-hash"
1664
+ version = "0.4.1"
1665
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1666
+ checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
1667
+ dependencies = [
1668
+ "generic-array",
1669
+ "subtle",
1670
+ ]
1671
+
1672
+ [[package]]
1673
+ name = "url"
1674
+ version = "2.3.1"
1675
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1676
+ checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
1677
+ dependencies = [
1678
+ "form_urlencoded",
1679
+ "idna",
1680
+ "percent-encoding",
1681
+ "serde",
1682
+ ]
1683
+
1684
+ [[package]]
1685
+ name = "value-bag"
1686
+ version = "1.0.0-alpha.9"
1687
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1688
+ checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
1689
+ dependencies = [
1690
+ "ctor",
1691
+ "erased-serde",
1692
+ "serde",
1693
+ "serde_fmt",
1694
+ "sval",
1695
+ "version_check",
1696
+ ]
1697
+
1698
+ [[package]]
1699
+ name = "version_check"
1700
+ version = "0.9.2"
1701
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1702
+ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1703
+
1704
+ [[package]]
1705
+ name = "waker-fn"
1706
+ version = "1.1.0"
1707
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1708
+ checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
1709
+
1710
+ [[package]]
1711
+ name = "wasi"
1712
+ version = "0.9.0+wasi-snapshot-preview1"
1713
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1714
+ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1715
+
1716
+ [[package]]
1717
+ name = "wasi"
1718
+ version = "0.10.0+wasi-snapshot-preview1"
1719
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1720
+ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1721
+
1722
+ [[package]]
1723
+ name = "wasi"
1724
+ version = "0.11.0+wasi-snapshot-preview1"
1725
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1726
+ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1727
+
1728
+ [[package]]
1729
+ name = "wasm-bindgen"
1730
+ version = "0.2.83"
1731
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1732
+ checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
1733
+ dependencies = [
1734
+ "cfg-if 1.0.0",
1735
+ "serde",
1736
+ "serde_json",
1737
+ "wasm-bindgen-macro",
1738
+ ]
1739
+
1740
+ [[package]]
1741
+ name = "wasm-bindgen-backend"
1742
+ version = "0.2.83"
1743
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1744
+ checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
1745
+ dependencies = [
1746
+ "bumpalo",
1747
+ "log",
1748
+ "once_cell",
1749
+ "proc-macro2",
1750
+ "quote",
1751
+ "syn",
1752
+ "wasm-bindgen-shared",
1753
+ ]
1754
+
1755
+ [[package]]
1756
+ name = "wasm-bindgen-futures"
1757
+ version = "0.4.33"
1758
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1759
+ checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
1760
+ dependencies = [
1761
+ "cfg-if 1.0.0",
1762
+ "js-sys",
1763
+ "wasm-bindgen",
1764
+ "web-sys",
1765
+ ]
1766
+
1767
+ [[package]]
1768
+ name = "wasm-bindgen-macro"
1769
+ version = "0.2.83"
1770
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1771
+ checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
1772
+ dependencies = [
1773
+ "quote",
1774
+ "wasm-bindgen-macro-support",
1775
+ ]
1776
+
1777
+ [[package]]
1778
+ name = "wasm-bindgen-macro-support"
1779
+ version = "0.2.83"
1780
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1781
+ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
1782
+ dependencies = [
1783
+ "proc-macro2",
1784
+ "quote",
1785
+ "syn",
1786
+ "wasm-bindgen-backend",
1787
+ "wasm-bindgen-shared",
1788
+ ]
1789
+
1790
+ [[package]]
1791
+ name = "wasm-bindgen-shared"
1792
+ version = "0.2.83"
1793
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1794
+ checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
1795
+
1796
+ [[package]]
1797
+ name = "web-sys"
1798
+ version = "0.3.60"
1799
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1800
+ checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
1801
+ dependencies = [
1802
+ "js-sys",
1803
+ "wasm-bindgen",
1804
+ ]
1805
+
1806
+ [[package]]
1807
+ name = "wepoll-ffi"
1808
+ version = "0.1.2"
1809
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1810
+ checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
1811
+ dependencies = [
1812
+ "cc",
1813
+ ]
1814
+
1815
+ [[package]]
1816
+ name = "winapi"
1817
+ version = "0.3.9"
1818
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1819
+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1820
+ dependencies = [
1821
+ "winapi-i686-pc-windows-gnu",
1822
+ "winapi-x86_64-pc-windows-gnu",
1823
+ ]
1824
+
1825
+ [[package]]
1826
+ name = "winapi-i686-pc-windows-gnu"
1827
+ version = "0.4.0"
1828
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1829
+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1830
+
1831
+ [[package]]
1832
+ name = "winapi-util"
1833
+ version = "0.1.5"
1834
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1835
+ checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1836
+ dependencies = [
1837
+ "winapi",
1838
+ ]
56
1839
 
57
- [metadata]
1840
+ [[package]]
58
- "checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
1841
+ name = "winapi-x86_64-pc-windows-gnu"
1842
+ version = "0.4.0"
59
- "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
1843
+ source = "registry+https://github.com/rust-lang/crates.io-index"
60
- "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
1844
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
61
- "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
Cargo.toml CHANGED
@@ -1,7 +1,21 @@
1
- [workspace]
1
+ [package]
2
+ name = "tide-jsx"
3
+ version = "0.4.0"
4
+ authors = ["pyrossh", "Gal Schlezinger <gal@spitfire.co.il>"]
5
+ edition = "2021"
6
+ description = "A safe and simple template engine with the ergonomics of JSX"
7
+ readme = "README.md"
8
+ repository = "https://github.com/pyrossh/tide-jsx"
9
+ keywords = ["jsx", "rsx", "html", "render", "template"]
10
+ categories = ["template-engine"]
11
+ license = "MIT"
2
12
 
3
- members = [
13
+ [dependencies]
14
+ tide-jsx-impl = { path = "impl", version = "0.3.0" }
15
+
16
+ [dev-dependencies]
4
- "render",
17
+ tide = "0.16.0"
5
- "render_macros",
18
+ pretty_assertions = "0.6"
19
+ async-std = { version = "1.9.0", features = ["attributes"] }
6
- "render_tests",
20
+ trybuild = "1.0"
7
- ]
21
+ tide-testing = "0.1.3"
LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Gal Schlezinger
4
+ Copyright (c) 2022 pyrossh
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,54 @@
1
+ # tide-jsx [![Build Status](https://github.com/pyrossh/tide-jsx/workflows/Test/badge.svg)](https://github.com/pyrossh/tide-jsx/actions?query=workflow%3ATest) [![crates.io](https://img.shields.io/crates/v/tide-jsx.svg)](https://crates.io/crates/tide-jsx)
2
+
3
+ This crate allows to use jsx like templating engine (which is a slightly modified version of [render.rs](https://github.com/render-rs/render.rs)) as templates in your tide request handlers.
4
+ Thanks to [@Schniz](https://github.com/Schniz) and all contributors for render.rs.
5
+
6
+ ## Example
7
+
8
+ ```rust
9
+ use tide::http::mime;
10
+ use tide::utils::After;
11
+ use tide::{log, Request, Response};
12
+ use tide_jsx::html::HTML5Doctype;
13
+ use tide_jsx::{component, rsx, view};
14
+
15
+ #[component]
16
+ fn Heading<'title>(title: &'title str) {
17
+ rsx! { <h1 class={"title"}>{title}</h1> }
18
+ }
19
+
20
+ async fn index(_req: Request<()>) -> tide::Result {
21
+ view! {
22
+ <>
23
+ <HTML5Doctype />
24
+ <html>
25
+ <head><title>{"Tide JSX"}</title></head>
26
+ <body>
27
+ <div>
28
+ <Heading title={"Hello world"} />
29
+ </div>
30
+ </body>
31
+ </html>
32
+ </>
33
+ }
34
+ }
35
+
36
+ #[async_std::main]
37
+ async fn main() -> tide::Result<()> {
38
+ log::start();
39
+ let mut app = tide::new();
40
+ app.with(tide::log::LogMiddleware::new());
41
+ app.with(After(|mut res: Response| async {
42
+ if let Some(err) = res.error() {
43
+ let msg = format!("<h1>Error: {:?}</h1>", err);
44
+ res.set_status(err.status());
45
+ res.set_content_type(mime::HTML);
46
+ res.set_body(msg);
47
+ }
48
+ Ok(res)
49
+ }));
50
+ app.at("/").get(index);
51
+ app.listen("127.0.0.1:5000").await?;
52
+ Ok(())
53
+ }
54
+ ```
examples/basic.rs ADDED
@@ -0,0 +1,45 @@
1
+ use tide::http::mime;
2
+ use tide::utils::After;
3
+ use tide::{log, Request, Response};
4
+ use tide_jsx::html::HTML5Doctype;
5
+ use tide_jsx::{component, rsx, view};
6
+
7
+ #[component]
8
+ fn Heading<'title>(title: &'title str) {
9
+ rsx! { <h1 class={"title"}>{title}</h1> }
10
+ }
11
+
12
+ async fn index(_req: Request<()>) -> tide::Result {
13
+ view! {
14
+ <>
15
+ <HTML5Doctype />
16
+ <html>
17
+ <head><title>{"Tide JSX"}</title></head>
18
+ <body>
19
+ <div>
20
+ <Heading title={"Hello world"} />
21
+ </div>
22
+ </body>
23
+ </html>
24
+ </>
25
+ }
26
+ }
27
+
28
+ #[async_std::main]
29
+ async fn main() -> tide::Result<()> {
30
+ log::start();
31
+ let mut app = tide::new();
32
+ app.with(tide::log::LogMiddleware::new());
33
+ app.with(After(|mut res: Response| async {
34
+ if let Some(err) = res.error() {
35
+ let msg = format!("<h1>Error: {:?}</h1>", err);
36
+ res.set_status(err.status());
37
+ res.set_content_type(mime::HTML);
38
+ res.set_body(msg);
39
+ }
40
+ Ok(res)
41
+ }));
42
+ app.at("/").get(index);
43
+ app.listen("127.0.0.1:5000").await?;
44
+ Ok(())
45
+ }
impl/Cargo.lock ADDED
@@ -0,0 +1,147 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 3
4
+
5
+ [[package]]
6
+ name = "ansi_term"
7
+ version = "0.11.0"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
10
+ dependencies = [
11
+ "winapi",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "ctor"
16
+ version = "0.1.23"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb"
19
+ dependencies = [
20
+ "quote",
21
+ "syn",
22
+ ]
23
+
24
+ [[package]]
25
+ name = "difference"
26
+ version = "2.0.0"
27
+ source = "registry+https://github.com/rust-lang/crates.io-index"
28
+ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
29
+
30
+ [[package]]
31
+ name = "output_vt100"
32
+ version = "0.1.3"
33
+ source = "registry+https://github.com/rust-lang/crates.io-index"
34
+ checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
35
+ dependencies = [
36
+ "winapi",
37
+ ]
38
+
39
+ [[package]]
40
+ name = "pretty_assertions"
41
+ version = "0.6.1"
42
+ source = "registry+https://github.com/rust-lang/crates.io-index"
43
+ checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
44
+ dependencies = [
45
+ "ansi_term",
46
+ "ctor",
47
+ "difference",
48
+ "output_vt100",
49
+ ]
50
+
51
+ [[package]]
52
+ name = "proc-macro-error"
53
+ version = "1.0.4"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
56
+ dependencies = [
57
+ "proc-macro-error-attr",
58
+ "proc-macro2",
59
+ "quote",
60
+ "syn",
61
+ "version_check",
62
+ ]
63
+
64
+ [[package]]
65
+ name = "proc-macro-error-attr"
66
+ version = "1.0.4"
67
+ source = "registry+https://github.com/rust-lang/crates.io-index"
68
+ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
69
+ dependencies = [
70
+ "proc-macro2",
71
+ "quote",
72
+ "version_check",
73
+ ]
74
+
75
+ [[package]]
76
+ name = "proc-macro2"
77
+ version = "1.0.43"
78
+ source = "registry+https://github.com/rust-lang/crates.io-index"
79
+ checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
80
+ dependencies = [
81
+ "unicode-ident",
82
+ ]
83
+
84
+ [[package]]
85
+ name = "quote"
86
+ version = "1.0.21"
87
+ source = "registry+https://github.com/rust-lang/crates.io-index"
88
+ checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
89
+ dependencies = [
90
+ "proc-macro2",
91
+ ]
92
+
93
+ [[package]]
94
+ name = "syn"
95
+ version = "1.0.99"
96
+ source = "registry+https://github.com/rust-lang/crates.io-index"
97
+ checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
98
+ dependencies = [
99
+ "proc-macro2",
100
+ "quote",
101
+ "unicode-ident",
102
+ ]
103
+
104
+ [[package]]
105
+ name = "tide-jsx-impl"
106
+ version = "0.3.0"
107
+ dependencies = [
108
+ "pretty_assertions",
109
+ "proc-macro-error",
110
+ "proc-macro2",
111
+ "quote",
112
+ "syn",
113
+ ]
114
+
115
+ [[package]]
116
+ name = "unicode-ident"
117
+ version = "1.0.4"
118
+ source = "registry+https://github.com/rust-lang/crates.io-index"
119
+ checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
120
+
121
+ [[package]]
122
+ name = "version_check"
123
+ version = "0.9.4"
124
+ source = "registry+https://github.com/rust-lang/crates.io-index"
125
+ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
126
+
127
+ [[package]]
128
+ name = "winapi"
129
+ version = "0.3.9"
130
+ source = "registry+https://github.com/rust-lang/crates.io-index"
131
+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
132
+ dependencies = [
133
+ "winapi-i686-pc-windows-gnu",
134
+ "winapi-x86_64-pc-windows-gnu",
135
+ ]
136
+
137
+ [[package]]
138
+ name = "winapi-i686-pc-windows-gnu"
139
+ version = "0.4.0"
140
+ source = "registry+https://github.com/rust-lang/crates.io-index"
141
+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
142
+
143
+ [[package]]
144
+ name = "winapi-x86_64-pc-windows-gnu"
145
+ version = "0.4.0"
146
+ source = "registry+https://github.com/rust-lang/crates.io-index"
147
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
impl/Cargo.toml ADDED
@@ -0,0 +1,23 @@
1
+ [package]
2
+ name = "tide-jsx-impl"
3
+ version = "0.3.0"
4
+ authors = ["pyrossh", "Gal Schlezinger <gal@spitfire.co.il>"]
5
+ edition = "2021"
6
+ description = "The macros needed for `render`"
7
+ readme = "../README.md"
8
+ repository = "https://github.com/pyrossh/tide-jsx"
9
+ keywords = ["macro"]
10
+ categories = []
11
+ license = "MIT"
12
+
13
+ [lib]
14
+ proc-macro = true
15
+
16
+ [dependencies]
17
+ syn = { version = "1.0", features = ["full"] }
18
+ quote = "1.0"
19
+ proc-macro2 = "1.0"
20
+ proc-macro-error = "1.0"
21
+
22
+ [dev-dependencies]
23
+ pretty_assertions = "0.6"
impl/src/child.rs ADDED
@@ -0,0 +1,37 @@
1
+ use crate::element::Element;
2
+ use quote::{quote, ToTokens};
3
+ use syn::parse::{Parse, ParseStream, Result};
4
+
5
+ pub enum Child {
6
+ Element(Element),
7
+ RawBlock(syn::Block),
8
+ }
9
+
10
+ impl ToTokens for Child {
11
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
12
+ match self {
13
+ Self::Element(element) => element.to_tokens(tokens),
14
+ Self::RawBlock(block) => {
15
+ let ts = if block.stmts.len() == 1 {
16
+ let first = &block.stmts[0];
17
+ quote!(#first)
18
+ } else {
19
+ quote!(#block)
20
+ };
21
+ ts.to_tokens(tokens);
22
+ }
23
+ }
24
+ }
25
+ }
26
+
27
+ impl Parse for Child {
28
+ fn parse(input: ParseStream) -> Result<Self> {
29
+ match input.parse::<Element>() {
30
+ Ok(element) => Ok(Self::Element(element)),
31
+ Err(_) => {
32
+ let block = input.parse::<syn::Block>()?;
33
+ Ok(Self::RawBlock(block))
34
+ }
35
+ }
36
+ }
37
+ }
impl/src/children.rs ADDED
@@ -0,0 +1,65 @@
1
+ use crate::child::Child;
2
+ use quote::{quote, ToTokens};
3
+ use syn::parse::{Parse, ParseStream, Result};
4
+
5
+ #[derive(Default)]
6
+ pub struct Children {
7
+ pub nodes: Vec<Child>,
8
+ }
9
+
10
+ impl Children {
11
+ pub fn new(nodes: Vec<Child>) -> Self {
12
+ Children { nodes }
13
+ }
14
+
15
+ pub fn len(&self) -> usize {
16
+ self.nodes.len()
17
+ }
18
+
19
+ pub fn as_option_of_tuples_tokens(&self) -> proc_macro2::TokenStream {
20
+ let children_quotes: Vec<_> = self
21
+ .nodes
22
+ .iter()
23
+ .map(|child| {
24
+ quote! { #child }
25
+ })
26
+ .collect();
27
+
28
+ match children_quotes.len() {
29
+ 0 => quote! { Option::<()>::None },
30
+ 1 => quote! { Some(#(#children_quotes),*) },
31
+ _ => {
32
+ let mut iter = children_quotes.iter();
33
+
34
+ let first = iter.next().unwrap();
35
+ let second = iter.next().unwrap();
36
+
37
+ let tuple_of_tuples = iter.fold(
38
+ quote!((#first, #second)),
39
+ |renderable, current| quote!((#renderable, #current)),
40
+ );
41
+
42
+ quote! { Some(#tuple_of_tuples) }
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ impl Parse for Children {
49
+ fn parse(input: ParseStream) -> Result<Self> {
50
+ let mut nodes = vec![];
51
+
52
+ while !input.peek(syn::Token![<]) || !input.peek2(syn::Token![/]) {
53
+ let child = input.parse::<Child>()?;
54
+ nodes.push(child);
55
+ }
56
+
57
+ Ok(Self::new(nodes))
58
+ }
59
+ }
60
+
61
+ impl ToTokens for Children {
62
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
63
+ self.as_option_of_tuples_tokens().to_tokens(tokens);
64
+ }
65
+ }
impl/src/element.rs ADDED
@@ -0,0 +1,68 @@
1
+ use crate::children::Children;
2
+ use crate::element_attributes::ElementAttributes;
3
+ use crate::tags::{ClosingTag, OpenTag};
4
+ use quote::{quote, ToTokens};
5
+ use syn::parse::{Parse, ParseStream, Result};
6
+
7
+ pub struct Element {
8
+ name: syn::Path,
9
+ attributes: ElementAttributes,
10
+ children: Children,
11
+ }
12
+
13
+ impl Parse for Element {
14
+ fn parse(input: ParseStream) -> Result<Self> {
15
+ let open_tag = input.parse::<OpenTag>()?;
16
+
17
+ let children = if open_tag.self_closing {
18
+ Children::default()
19
+ } else {
20
+ let children = input.parse::<Children>()?;
21
+ let closing_tag = input.parse::<ClosingTag>()?;
22
+ closing_tag.validate(&open_tag);
23
+ children
24
+ };
25
+
26
+ Ok(Element {
27
+ name: open_tag.name,
28
+ attributes: open_tag.attributes,
29
+ children,
30
+ })
31
+ }
32
+ }
33
+
34
+ impl Element {
35
+ pub fn is_custom_element(&self) -> bool {
36
+ match self.name.get_ident() {
37
+ None => true,
38
+ Some(ident) => {
39
+ let name = ident.to_string();
40
+ let first_letter = name.get(0..1).unwrap();
41
+ first_letter.to_uppercase() == first_letter
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ impl ToTokens for Element {
48
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
49
+ let name = &self.name;
50
+
51
+ let declaration = if self.is_custom_element() {
52
+ let attrs = self.attributes.for_custom_element(&self.children);
53
+ quote! { #name #attrs }
54
+ } else {
55
+ let attrs = self.attributes.for_simple_element();
56
+ let children_tuple = self.children.as_option_of_tuples_tokens();
57
+ quote! {
58
+ tide_jsx::SimpleElement {
59
+ tag_name: stringify!(#name),
60
+ attributes: #attrs,
61
+ contents: #children_tuple,
62
+ }
63
+ }
64
+ };
65
+
66
+ declaration.to_tokens(tokens);
67
+ }
68
+ }
impl/src/element_attribute.rs ADDED
@@ -0,0 +1,109 @@
1
+ use quote::quote;
2
+ use std::hash::{Hash, Hasher};
3
+ use syn::ext::IdentExt;
4
+ use syn::parse::{Parse, ParseStream, Result};
5
+ use syn::spanned::Spanned;
6
+
7
+ pub type AttributeKey = syn::punctuated::Punctuated<syn::Ident, syn::Token![-]>;
8
+
9
+ pub enum ElementAttribute {
10
+ Punned(AttributeKey),
11
+ WithValue(AttributeKey, syn::Block),
12
+ }
13
+
14
+ impl ElementAttribute {
15
+ pub fn ident(&self) -> &AttributeKey {
16
+ match self {
17
+ Self::Punned(ident) | Self::WithValue(ident, _) => ident,
18
+ }
19
+ }
20
+
21
+ pub fn idents(&self) -> Vec<&syn::Ident> {
22
+ self.ident().iter().collect::<Vec<_>>()
23
+ }
24
+
25
+ pub fn value_tokens(&self) -> proc_macro2::TokenStream {
26
+ match self {
27
+ Self::WithValue(_, value) => {
28
+ if value.stmts.len() == 1 {
29
+ let first = &value.stmts[0];
30
+ quote!(#first)
31
+ } else {
32
+ quote!(#value)
33
+ }
34
+ }
35
+ Self::Punned(ident) => quote!(#ident),
36
+ }
37
+ }
38
+
39
+ pub fn validate(self, is_custom_element: bool) -> Result<Self> {
40
+ if is_custom_element {
41
+ self.validate_for_custom_element()
42
+ } else {
43
+ self.validate_for_simple_element()
44
+ }
45
+ }
46
+
47
+ pub fn validate_for_custom_element(self) -> Result<Self> {
48
+ if self.idents().len() < 2 {
49
+ Ok(self)
50
+ } else {
51
+ let alternative_name = self
52
+ .idents()
53
+ .iter()
54
+ .map(|x| x.to_string())
55
+ .collect::<Vec<_>>()
56
+ .join("_");
57
+
58
+ let error_message = format!(
59
+ "Can't use dash-delimited values on custom components. Did you mean `{}`?",
60
+ alternative_name
61
+ );
62
+
63
+ Err(syn::Error::new(self.ident().span(), error_message))
64
+ }
65
+ }
66
+
67
+ pub fn validate_for_simple_element(self) -> Result<Self> {
68
+ match (&self, self.idents().len()) {
69
+ (Self::Punned(ref key), len) if len > 1 => {
70
+ let error_message = "Can't use punning with dash-delimited values";
71
+ Err(syn::Error::new(key.span(), error_message))
72
+ }
73
+ _ => Ok(self),
74
+ }
75
+ }
76
+ }
77
+
78
+ impl PartialEq for ElementAttribute {
79
+ fn eq(&self, other: &Self) -> bool {
80
+ let self_idents: Vec<_> = self.ident().iter().collect();
81
+ let other_idents: Vec<_> = other.ident().iter().collect();
82
+ self_idents == other_idents
83
+ }
84
+ }
85
+
86
+ impl Eq for ElementAttribute {}
87
+
88
+ impl Hash for ElementAttribute {
89
+ fn hash<H: Hasher>(&self, state: &mut H) {
90
+ let ident = self.idents();
91
+ Hash::hash(&ident, state)
92
+ }
93
+ }
94
+
95
+ impl Parse for ElementAttribute {
96
+ fn parse(input: ParseStream) -> Result<Self> {
97
+ let name = AttributeKey::parse_separated_nonempty_with(input, syn::Ident::parse_any)?;
98
+ let not_punned = input.peek(syn::Token![=]);
99
+
100
+ if !not_punned {
101
+ return Ok(Self::Punned(name));
102
+ }
103
+
104
+ input.parse::<syn::Token![=]>()?;
105
+ let value = input.parse::<syn::Block>()?;
106
+
107
+ Ok(Self::WithValue(name, value))
108
+ }
109
+ }
impl/src/element_attributes.rs ADDED
@@ -0,0 +1,148 @@
1
+ use crate::children::Children;
2
+ use crate::element_attribute::ElementAttribute;
3
+ use proc_macro_error::emit_error;
4
+ use quote::{quote, ToTokens};
5
+ use std::collections::HashSet;
6
+ use syn::ext::IdentExt;
7
+ use syn::parse::{Parse, ParseStream, Result};
8
+ use syn::spanned::Spanned;
9
+
10
+ pub type Attributes = HashSet<ElementAttribute>;
11
+
12
+ #[derive(Default)]
13
+ pub struct ElementAttributes {
14
+ pub attributes: Attributes,
15
+ }
16
+
17
+ impl ElementAttributes {
18
+ pub fn new(attributes: Attributes) -> Self {
19
+ Self { attributes }
20
+ }
21
+
22
+ pub fn for_custom_element<'c>(
23
+ &self,
24
+ children: &'c Children,
25
+ ) -> CustomElementAttributes<'_, 'c> {
26
+ CustomElementAttributes {
27
+ attributes: &self.attributes,
28
+ children,
29
+ }
30
+ }
31
+
32
+ pub fn for_simple_element(&self) -> SimpleElementAttributes<'_> {
33
+ SimpleElementAttributes {
34
+ attributes: &self.attributes,
35
+ }
36
+ }
37
+
38
+ pub fn parse(input: ParseStream, is_custom_element: bool) -> Result<Self> {
39
+ let mut parsed_self = input.parse::<Self>()?;
40
+
41
+ let new_attributes: Attributes = parsed_self
42
+ .attributes
43
+ .drain()
44
+ .filter_map(|attribute| match attribute.validate(is_custom_element) {
45
+ Ok(x) => Some(x),
46
+ Err(err) => {
47
+ emit_error!(err.span(), "Invalid attribute: {}", err);
48
+ None
49
+ }
50
+ })
51
+ .collect();
52
+
53
+ Ok(ElementAttributes::new(new_attributes))
54
+ }
55
+ }
56
+
57
+ impl Parse for ElementAttributes {
58
+ fn parse(input: ParseStream) -> Result<Self> {
59
+ let mut attributes: HashSet<ElementAttribute> = HashSet::new();
60
+ while input.peek(syn::Ident::peek_any) {
61
+ let attribute = input.parse::<ElementAttribute>()?;
62
+ let ident = attribute.ident();
63
+ if attributes.contains(&attribute) {
64
+ emit_error!(
65
+ ident.span(),
66
+ "There is a previous definition of the {} attribute",
67
+ quote!(#ident)
68
+ );
69
+ }
70
+ attributes.insert(attribute);
71
+ }
72
+ Ok(ElementAttributes::new(attributes))
73
+ }
74
+ }
75
+
76
+ pub struct CustomElementAttributes<'a, 'c> {
77
+ attributes: &'a Attributes,
78
+ children: &'c Children,
79
+ }
80
+
81
+ impl<'a, 'c> ToTokens for CustomElementAttributes<'a, 'c> {
82
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
83
+ let mut attrs: Vec<_> = self
84
+ .attributes
85
+ .iter()
86
+ .map(|attribute| {
87
+ let ident = attribute.ident();
88
+ let value = attribute.value_tokens();
89
+
90
+ quote! {
91
+ #ident: #value
92
+ }
93
+ })
94
+ .collect();
95
+
96
+ if self.children.len() > 0 {
97
+ let children_tuple = self.children.as_option_of_tuples_tokens();
98
+ attrs.push(quote! {
99
+ children: #children_tuple
100
+ });
101
+ }
102
+
103
+ let quoted = if attrs.len() == 0 {
104
+ quote!()
105
+ } else {
106
+ quote!({ #(#attrs),* })
107
+ };
108
+
109
+ quoted.to_tokens(tokens);
110
+ }
111
+ }
112
+
113
+ pub struct SimpleElementAttributes<'a> {
114
+ attributes: &'a Attributes,
115
+ }
116
+
117
+ impl<'a> ToTokens for SimpleElementAttributes<'a> {
118
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
119
+ if self.attributes.is_empty() {
120
+ quote!(None).to_tokens(tokens);
121
+ } else {
122
+ let attrs: Vec<_> = self
123
+ .attributes
124
+ .iter()
125
+ .map(|attribute| {
126
+ let mut iter = attribute.ident().iter();
127
+ let first_word = iter.next().unwrap().unraw();
128
+ let ident = iter.fold(first_word.to_string(), |acc, curr| {
129
+ format!("{}-{}", acc, curr.unraw())
130
+ });
131
+ let value = attribute.value_tokens();
132
+
133
+ quote! {
134
+ hm.insert(#ident, ::std::borrow::Cow::from(#value));
135
+ }
136
+ })
137
+ .collect();
138
+
139
+ let hashmap_declaration = quote! {{
140
+ let mut hm = std::collections::HashMap::<&str, ::std::borrow::Cow<'_, str>>::new();
141
+ #(#attrs)*
142
+ Some(hm)
143
+ }};
144
+
145
+ hashmap_declaration.to_tokens(tokens);
146
+ }
147
+ }
148
+ }
impl/src/function_component.rs ADDED
@@ -0,0 +1,57 @@
1
+ use proc_macro::TokenStream;
2
+ use proc_macro_error::emit_error;
3
+ use quote::quote;
4
+ use syn::spanned::Spanned;
5
+
6
+ pub fn create_function_component(f: syn::ItemFn) -> TokenStream {
7
+ let struct_name = f.sig.ident;
8
+ let (impl_generics, ty_generics, where_clause) = f.sig.generics.split_for_impl();
9
+ let inputs = f.sig.inputs;
10
+ let block = f.block;
11
+ let vis = f.vis;
12
+
13
+ let inputs_block = if inputs.len() > 0 {
14
+ let input_names: Vec<_> = inputs.iter().collect();
15
+
16
+ quote!({ #(#vis #input_names),* })
17
+ } else {
18
+ quote!(;)
19
+ };
20
+
21
+ let inputs_reading = if inputs.len() == 0 {
22
+ quote!()
23
+ } else {
24
+ let input_names: Vec<_> = inputs
25
+ .iter()
26
+ .filter_map(|argument| match argument {
27
+ syn::FnArg::Typed(typed) => Some(typed),
28
+ syn::FnArg::Receiver(rec) => {
29
+ emit_error!(rec.span(), "Don't use `self` on components");
30
+ None
31
+ }
32
+ })
33
+ .map(|value| {
34
+ let pat = &value.pat;
35
+ quote!(#pat)
36
+ })
37
+ .collect();
38
+ quote!(
39
+ let #struct_name { #(#input_names),* } = self;
40
+ )
41
+ };
42
+
43
+ TokenStream::from(quote! {
44
+ #[derive(Debug)]
45
+ #vis struct #struct_name #impl_generics #inputs_block
46
+
47
+ impl #impl_generics tide_jsx::Render for #struct_name #ty_generics #where_clause {
48
+ fn render_into<W: std::fmt::Write>(self, w: &mut W) -> std::fmt::Result {
49
+ let result = {
50
+ #inputs_reading
51
+ #block
52
+ };
53
+ tide_jsx::Render::render_into(result, w)
54
+ }
55
+ }
56
+ })
57
+ }
impl/src/lib.rs ADDED
@@ -0,0 +1,52 @@
1
+ extern crate proc_macro;
2
+
3
+ mod child;
4
+ mod children;
5
+ mod element;
6
+ mod element_attribute;
7
+ mod element_attributes;
8
+ mod function_component;
9
+ mod tags;
10
+
11
+ use element::Element;
12
+ use proc_macro::TokenStream;
13
+ use proc_macro_error::proc_macro_error;
14
+ use quote::quote;
15
+ use syn::parse_macro_input;
16
+
17
+ #[proc_macro]
18
+ #[proc_macro_error]
19
+ pub fn html(input: TokenStream) -> TokenStream {
20
+ let el = proc_macro2::TokenStream::from(rsx(input));
21
+ let result = quote! { ::tide_jsx::Render::render(#el) };
22
+ TokenStream::from(result)
23
+ }
24
+
25
+ /// Generate a renderable component tree, before rendering it
26
+ #[proc_macro]
27
+ #[proc_macro_error]
28
+ pub fn rsx(input: TokenStream) -> TokenStream {
29
+ let el = parse_macro_input!(input as Element);
30
+ let result = quote! { #el };
31
+ TokenStream::from(result)
32
+ }
33
+
34
+ #[proc_macro]
35
+ #[proc_macro_error]
36
+ pub fn view(input: TokenStream) -> TokenStream {
37
+ let el = parse_macro_input!(input as Element);
38
+ let result = quote! {
39
+ Ok(::tide::Response::builder(tide::http::StatusCode::Ok)
40
+ .content_type(::tide::http::mime::HTML)
41
+ .body(::tide_jsx::Render::render(#el))
42
+ .build())
43
+ };
44
+ TokenStream::from(result)
45
+ }
46
+
47
+ #[proc_macro_attribute]
48
+ #[proc_macro_error]
49
+ pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
50
+ let f = parse_macro_input!(item as syn::ItemFn);
51
+ function_component::create_function_component(f)
52
+ }
impl/src/tags.rs ADDED
@@ -0,0 +1,78 @@
1
+ use crate::element_attributes::ElementAttributes;
2
+ use proc_macro_error::abort;
3
+ use quote::quote;
4
+ use syn::parse::{Parse, ParseStream, Result};
5
+ use syn::spanned::Spanned;
6
+
7
+ pub struct OpenTag {
8
+ pub name: syn::Path,
9
+ pub attributes: ElementAttributes,
10
+ pub self_closing: bool,
11
+ pub is_custom_element: bool,
12
+ }
13
+
14
+ fn name_or_fragment(maybe_name: Result<syn::Path>) -> syn::Path {
15
+ maybe_name.unwrap_or_else(|_| syn::parse_str::<syn::Path>("tide_jsx::Fragment").unwrap())
16
+ }
17
+
18
+ fn is_custom_element_name(path: &syn::Path) -> bool {
19
+ match path.get_ident() {
20
+ None => true,
21
+ Some(ident) => {
22
+ let name = ident.to_string();
23
+ let first_letter = name.get(0..1).unwrap();
24
+ first_letter.to_uppercase() == first_letter
25
+ }
26
+ }
27
+ }
28
+
29
+ impl Parse for OpenTag {
30
+ fn parse(input: ParseStream) -> Result<Self> {
31
+ input.parse::<syn::Token![<]>()?;
32
+ let maybe_name = syn::Path::parse_mod_style(input);
33
+ let name = name_or_fragment(maybe_name);
34
+ let is_custom_element = is_custom_element_name(&name);
35
+ let attributes = ElementAttributes::parse(input, is_custom_element)?;
36
+ let self_closing = input.parse::<syn::Token![/]>().is_ok();
37
+ input.parse::<syn::Token![>]>()?;
38
+
39
+ Ok(Self {
40
+ name,
41
+ attributes,
42
+ self_closing,
43
+ is_custom_element,
44
+ })
45
+ }
46
+ }
47
+
48
+ pub struct ClosingTag {
49
+ name: syn::Path,
50
+ }
51
+
52
+ impl ClosingTag {
53
+ pub fn validate(&self, open_tag: &OpenTag) {
54
+ let open_tag_path = &open_tag.name;
55
+ let open_tag_path_str = quote!(#open_tag_path).to_string();
56
+ let self_path = &self.name;
57
+ let self_path_str = quote!(#self_path).to_string();
58
+ if self_path_str != open_tag_path_str {
59
+ abort!(
60
+ self.name.span(),
61
+ "Expected closing tag for: <{}>",
62
+ &open_tag_path_str
63
+ );
64
+ }
65
+ }
66
+ }
67
+
68
+ impl Parse for ClosingTag {
69
+ fn parse(input: ParseStream) -> Result<Self> {
70
+ input.parse::<syn::Token![<]>()?;
71
+ input.parse::<syn::Token![/]>()?;
72
+ let maybe_name = input.parse::<syn::Path>();
73
+ input.parse::<syn::Token![>]>()?;
74
+ Ok(Self {
75
+ name: name_or_fragment(maybe_name),
76
+ })
77
+ }
78
+ }
render/Cargo.toml DELETED
@@ -1,10 +0,0 @@
1
- [package]
2
- name = "render"
3
- version = "0.1.0"
4
- authors = ["Gal Schlezinger <gal@spitfire.co.il>"]
5
- edition = "2018"
6
-
7
- # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
-
9
- [dependencies]
10
- render_macros = { path = "../render_macros" }
render/src/fragment.rs DELETED
@@ -1,28 +0,0 @@
1
- use crate::Renderable;
2
-
3
- /// A top-level root component to combine a same-level components
4
- /// in a RSX fashion
5
- ///
6
- /// ```rust
7
- /// # #![feature(proc_macro_hygiene)]
8
- /// # use render::html::HTML5Doctype;
9
- /// # use render_macros::html;
10
- /// # use render::fragment::Fragment;
11
- /// let result = html! {
12
- /// <Fragment>
13
- /// <a />
14
- /// <b />
15
- /// </Fragment>
16
- /// };
17
- /// assert_eq!(result, "<a /><b />");
18
- /// ```
19
- #[derive(Debug)]
20
- pub struct Fragment<T: Renderable> {
21
- pub children: T,
22
- }
23
-
24
- impl<T: Renderable> Renderable for Fragment<T> {
25
- fn render(self) -> String {
26
- self.children.render()
27
- }
28
- }
render/src/html.rs DELETED
@@ -1,28 +0,0 @@
1
- use crate::Renderable;
2
-
3
- /// HTML 5 doctype declaration
4
- ///
5
- /// ```rust
6
- /// # #![feature(proc_macro_hygiene)]
7
- /// # use render::html::HTML5Doctype;
8
- /// # use render::html;
9
- /// # use render::fragment::Fragment;
10
- /// # let result =
11
- /// html! {
12
- /// <Fragment>
13
- /// <HTML5Doctype />
14
- /// <html>
15
- /// <body />
16
- /// </html>
17
- /// </Fragment>
18
- /// };
19
- /// # assert_eq!(result, "<!DOCTYPE html><html><body /></html>");
20
- /// ```
21
- #[derive(Debug)]
22
- pub struct HTML5Doctype;
23
-
24
- impl Renderable for HTML5Doctype {
25
- fn render(self) -> String {
26
- "<!DOCTYPE html>".to_string()
27
- }
28
- }
render/src/lib.rs DELETED
@@ -1,10 +0,0 @@
1
- pub mod fragment;
2
- pub mod html;
3
- mod renderable;
4
- mod simple_element;
5
- mod text_element;
6
-
7
- pub use fragment::Fragment;
8
- pub use renderable::Renderable;
9
- pub use render_macros::{html, rsx};
10
- pub use simple_element::SimpleElement;
render/src/renderable.rs DELETED
@@ -1,41 +0,0 @@
1
- /// A renderable component
2
- pub trait Renderable: core::fmt::Debug + Sized {
3
- /// Render the component to the HTML representation.
4
- ///
5
- /// Mostly done using the `html!` macro to generate strings
6
- /// by composing tags.
7
- fn render(self) -> String;
8
- }
9
-
10
- impl Renderable for () {
11
- fn render(self) -> String {
12
- "".to_string()
13
- }
14
- }
15
-
16
- impl<A: Renderable, B: Renderable> Renderable for (A, B) {
17
- fn render(self) -> String {
18
- format!("{}{}", self.0.render(), self.1.render())
19
- }
20
- }
21
-
22
- impl<A: Renderable, B: Renderable, C: Renderable> Renderable for (A, B, C) {
23
- fn render(self) -> String {
24
- ((self.0, self.1), self.2).render()
25
- }
26
- }
27
-
28
- impl<A: Renderable, B: Renderable, C: Renderable, D: Renderable> Renderable for (A, B, C, D) {
29
- fn render(self) -> String {
30
- ((self.0, self.1), (self.2, self.3)).render()
31
- }
32
- }
33
-
34
- impl<T: Renderable> Renderable for Option<T> {
35
- fn render(self) -> String {
36
- match self {
37
- None => "".to_string(),
38
- Some(x) => x.render(),
39
- }
40
- }
41
- }
render/src/simple_element.rs DELETED
@@ -1,41 +0,0 @@
1
- use crate::Renderable;
2
- use std::collections::HashMap;
3
-
4
- /// Simple HTML element tag
5
- #[derive(Debug)]
6
- pub struct SimpleElement<'a, T: Renderable> {
7
- /// the HTML tag name, like `html`, `head`, `body`, `link`...
8
- pub tag_name: &'a str,
9
- pub attributes: Option<HashMap<&'a str, &'a str>>,
10
- pub contents: Option<T>,
11
- }
12
-
13
- fn attributes_to_string<Key: std::fmt::Display + std::hash::Hash, Value: std::fmt::Debug>(
14
- opt: &Option<HashMap<Key, Value>>,
15
- ) -> String {
16
- match opt {
17
- None => "".to_string(),
18
- Some(map) => {
19
- let s: String = map
20
- .iter()
21
- .map(|(key, value)| format!(" {}={:?}", key, value))
22
- .collect();
23
- s
24
- }
25
- }
26
- }
27
-
28
- impl<'a, T: Renderable> Renderable for SimpleElement<'a, T> {
29
- fn render(self) -> String {
30
- let attrs = attributes_to_string(&self.attributes);
31
- match self.contents {
32
- None => format!("<{}{} />", self.tag_name, attrs),
33
- Some(renderable) => format!(
34
- "<{tag_name}{attrs}>{contents}</{tag_name}>",
35
- tag_name = self.tag_name,
36
- attrs = attrs,
37
- contents = renderable.render()
38
- ),
39
- }
40
- }
41
- }
render/src/text_element.rs DELETED
@@ -1,13 +0,0 @@
1
- use crate::Renderable;
2
-
3
- impl Renderable for String {
4
- fn render(self) -> String {
5
- self
6
- }
7
- }
8
-
9
- impl Renderable for &str {
10
- fn render(self) -> String {
11
- self.to_string()
12
- }
13
- }
render_macros/Cargo.toml DELETED
@@ -1,15 +0,0 @@
1
- [package]
2
- name = "render_macros"
3
- version = "0.1.0"
4
- authors = ["Gal Schlezinger <gal@spitfire.co.il>"]
5
- edition = "2018"
6
-
7
- # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
-
9
- [lib]
10
- proc-macro = true
11
-
12
- [dependencies]
13
- syn = { version = "1.0", features = ["full"] }
14
- quote = "1.0"
15
- proc-macro2 = "1.0"
render_macros/src/element_attribute.rs DELETED
@@ -1,52 +0,0 @@
1
- use quote::quote;
2
- use syn::parse::{Parse, ParseStream, Result};
3
-
4
- pub enum ElementAttribute {
5
- Punned(syn::Ident),
6
- WithValue(syn::Ident, syn::Block),
7
- }
8
-
9
- impl ElementAttribute {
10
- pub fn ident(&self) -> &syn::Ident {
11
- match self {
12
- Self::Punned(ident) | Self::WithValue(ident, _) => ident,
13
- }
14
- }
15
-
16
- pub fn value_tokens(&self) -> proc_macro2::TokenStream {
17
- match self {
18
- Self::WithValue(_, value) => quote!(#value),
19
- Self::Punned(ident) => quote!(#ident),
20
- }
21
- }
22
- }
23
-
24
- impl PartialEq for ElementAttribute {
25
- fn eq(&self, other: &Self) -> bool {
26
- self.ident() == other.ident()
27
- }
28
- }
29
-
30
- impl Eq for ElementAttribute {}
31
-
32
- impl std::hash::Hash for ElementAttribute {
33
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
34
- std::hash::Hash::hash(self.ident(), state)
35
- }
36
- }
37
-
38
- impl Parse for ElementAttribute {
39
- fn parse(input: ParseStream) -> Result<Self> {
40
- let name = input.parse::<syn::Ident>()?;
41
- let not_punned = input.peek(syn::Token![=]);
42
-
43
- if !not_punned {
44
- return Ok(Self::Punned(name));
45
- }
46
-
47
- input.parse::<syn::Token![=]>()?;
48
- let value = input.parse::<syn::Block>()?;
49
-
50
- Ok(Self::WithValue(name, value))
51
- }
52
- }
render_macros/src/lib.rs DELETED
@@ -1,220 +0,0 @@
1
- #![feature(proc_macro_diagnostic, proc_macro_hygiene)]
2
-
3
- // TODO: Extract a `Children` struct that can implement `Parse` and `ToTokens`:
4
- // - `Parse` will do the nasty things inside `Element`
5
- // - `ToTokens` will do the trick with the tuples
6
-
7
- extern crate proc_macro;
8
-
9
- mod element_attribute;
10
-
11
- use element_attribute::ElementAttribute;
12
- use proc_macro::TokenStream;
13
- use quote::{quote, ToTokens};
14
- use std::collections::HashSet;
15
- use syn::parse::{Parse, ParseStream, Result};
16
- use syn::parse_macro_input;
17
-
18
- struct Element {
19
- name: syn::Ident,
20
- attributes: HashSet<ElementAttribute>,
21
- children: Vec<RenderableItem>,
22
- }
23
-
24
- enum RenderableItem {
25
- Element(Element),
26
- RawBlock(syn::Block),
27
- }
28
-
29
- impl ToTokens for RenderableItem {
30
- fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
31
- match self {
32
- Self::Element(element) => element.to_tokens(tokens),
33
- Self::RawBlock(block) => {
34
- let ts = quote! { #block };
35
- ts.to_tokens(tokens);
36
- }
37
- }
38
- }
39
- }
40
-
41
- impl Parse for RenderableItem {
42
- fn parse(input: ParseStream) -> Result<Self> {
43
- match input.parse::<Element>() {
44
- Ok(element) => Ok(Self::Element(element)),
45
- Err(_) => {
46
- let block = input.parse::<syn::Block>()?;
47
- Ok(Self::RawBlock(block))
48
- }
49
- }
50
- }
51
- }
52
-
53
- impl Parse for Element {
54
- fn parse(input: ParseStream) -> Result<Self> {
55
- let mut attributes: HashSet<ElementAttribute> = HashSet::new();
56
- let _starts_a_tag = input.parse::<syn::Token![<]>().is_ok();
57
-
58
- let name = input.parse()?;
59
-
60
- while input.peek(syn::Ident) {
61
- if let Ok(attribute) = input.parse::<ElementAttribute>() {
62
- if attributes.contains(&attribute) {
63
- let error_message = format!(
64
- "There is a previous definition of the {} attribute",
65
- attribute.ident()
66
- );
67
- attribute
68
- .ident()
69
- .span()
70
- .unwrap()
71
- .warning(error_message)
72
- .emit();
73
- }
74
- attributes.insert(attribute);
75
- }
76
- }
77
-
78
- let can_have_contents = input.parse::<syn::Token![/]>().is_err();
79
- input.parse::<syn::Token![>]>()?;
80
-
81
- let mut children = vec![];
82
-
83
- if can_have_contents {
84
- while !input.peek(syn::Token![<]) || !input.peek2(syn::Token![/]) {
85
- if let Ok(child) = input.parse::<RenderableItem>() {
86
- children.push(child);
87
- }
88
- }
89
-
90
- // parse closing
91
- input.parse::<syn::Token![<]>()?;
92
- input.parse::<syn::Token![/]>()?;
93
- let closing_name: syn::Ident = input.parse()?;
94
- if closing_name != name {
95
- let error_message = format!("Expected closing tag for: <{}>", &name);
96
- closing_name.span().unwrap().error(error_message).emit();
97
- }
98
- input.parse::<syn::Token![>]>()?;
99
- }
100
-
101
- Ok(Element {
102
- name,
103
- attributes,
104
- children,
105
- })
106
- }
107
- }
108
-
109
- impl Element {
110
- pub fn is_custom_element(&self) -> bool {
111
- let name = self.name.to_string();
112
- let first_letter = name.get(0..1).unwrap();
113
- first_letter.to_uppercase() == first_letter
114
- }
115
- }
116
-
117
- impl ToTokens for Element {
118
- fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
119
- let Element { name, children, .. } = self;
120
-
121
- let children_quotes: Vec<_> = children
122
- .iter()
123
- .map(|child| {
124
- quote! { #child }
125
- })
126
- .collect();
127
- let children_tuple = match children_quotes.len() {
128
- 0 => quote! { Option::<()>::None },
129
- 1 => quote! { Some(#(#children_quotes)*) },
130
- _ => {
131
- let mut iter = children_quotes.iter();
132
- let first = iter.next().unwrap();
133
- let second = iter.next().unwrap();
134
- let tuple_of_tuples = iter.fold(
135
- quote!((#first, #second)),
136
- |renderable, current| quote!((#current, #renderable)),
137
- );
138
-
139
- quote! { Some(#tuple_of_tuples) }
140
- }
141
- };
142
-
143
- let declaration = if self.is_custom_element() {
144
- let mut attrs: Vec<_> = self
145
- .attributes
146
- .iter()
147
- .map(|attribute| {
148
- let ident = attribute.ident();
149
- let value = attribute.value_tokens();
150
-
151
- quote! {
152
- #ident: #value
153
- }
154
- })
155
- .collect();
156
-
157
- if children_quotes.len() > 0 {
158
- attrs.push(quote! {
159
- children: #children_tuple
160
- });
161
- }
162
-
163
- if attrs.len() == 0 {
164
- quote! { #name }
165
- } else {
166
- quote! {
167
- #name {
168
- #(#attrs),*
169
- }
170
- }
171
- }
172
- } else {
173
- let attrs: Vec<_> = self
174
- .attributes
175
- .iter()
176
- .map(|attribute| {
177
- let ident = attribute.ident();
178
- let value = attribute.value_tokens();
179
-
180
- quote! {
181
- hm.insert(stringify!(#ident), #value);
182
- }
183
- })
184
- .collect();
185
- let attributes_value = if self.attributes.len() == 0 {
186
- quote!(None)
187
- } else {
188
- quote! {{
189
- let mut hm = std::collections::HashMap::<&str, &str>::new();
190
- #(#attrs)*
191
- Some(hm)
192
- }}
193
- };
194
- quote! {
195
- ::render::SimpleElement {
196
- tag_name: stringify!(#name),
197
- attributes: #attributes_value,
198
- contents: #children_tuple,
199
- }
200
- }
201
- };
202
- declaration.to_tokens(tokens);
203
- }
204
- }
205
-
206
- /// Render a component tree to an HTML string
207
- #[proc_macro]
208
- pub fn html(input: TokenStream) -> TokenStream {
209
- let el = proc_macro2::TokenStream::from(rsx(input));
210
- let result = quote! { ::render::Renderable::render(#el) };
211
- TokenStream::from(result)
212
- }
213
-
214
- /// Generate a renderable component tree
215
- #[proc_macro]
216
- pub fn rsx(input: TokenStream) -> TokenStream {
217
- let el = parse_macro_input!(input as Element);
218
- let result = quote! { #el };
219
- TokenStream::from(result)
220
- }
render_tests/Cargo.toml DELETED
@@ -1,11 +0,0 @@
1
- [package]
2
- name = "render_tests"
3
- version = "0.1.0"
4
- authors = ["Gal Schlezinger <gal@spitfire.co.il>"]
5
- edition = "2018"
6
- publish = false
7
-
8
- # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9
-
10
- [dependencies]
11
- render = { path = "../render" }
render_tests/src/lib.rs DELETED
@@ -1,46 +0,0 @@
1
- #![feature(proc_macro_hygiene)]
2
-
3
- use render::html::HTML5Doctype;
4
- use render::{html, rsx, Renderable, Fragment};
5
-
6
- #[derive(Debug)]
7
- struct Hello<'a, T: Renderable> {
8
- world: &'a str,
9
- yes: i32,
10
- children: T,
11
- }
12
-
13
- impl<'a, T: Renderable> Renderable for Hello<'a, T> {
14
- fn render(self) -> String {
15
- html! {
16
- <b class={"some_bem_class"}>
17
- {format!("{}", self.world)}
18
- <br />
19
- {format!("A number: {}", self.yes)}
20
- {self.children}
21
- </b>
22
- }
23
- }
24
- }
25
-
26
- pub fn it_works() -> String {
27
- let world = "hello";
28
- let other_value = rsx! {
29
- <em>{format!("hello world?")}</em>
30
- };
31
- let value = html! {
32
- <Fragment>
33
- <HTML5Doctype />
34
- <Hello world yes={1 + 1}>
35
- <div>{format!("HEY!")}</div>
36
- {other_value}
37
- </Hello>
38
- </Fragment>
39
- };
40
- value
41
- }
42
-
43
- #[test]
44
- pub fn verify_works() {
45
- println!("{}", it_works());
46
- }
src/fragment.rs ADDED
@@ -0,0 +1,13 @@
1
+ use crate::Render;
2
+ use std::fmt::{Result, Write};
3
+
4
+ #[derive(Debug)]
5
+ pub struct Fragment<T: Render> {
6
+ pub children: T,
7
+ }
8
+
9
+ impl<T: Render> Render for Fragment<T> {
10
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
11
+ self.children.render_into(writer)
12
+ }
13
+ }
src/html.rs ADDED
@@ -0,0 +1,11 @@
1
+ use crate::Render;
2
+ use std::fmt::{Result, Write};
3
+
4
+ #[derive(Debug)]
5
+ pub struct HTML5Doctype;
6
+
7
+ impl Render for HTML5Doctype {
8
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
9
+ write!(writer, "<!DOCTYPE html>")
10
+ }
11
+ }
src/html_escaping.rs ADDED
@@ -0,0 +1,16 @@
1
+ use std::fmt::{Result, Write};
2
+
3
+ pub fn escape_html<W: Write>(html: &str, writer: &mut W) -> Result {
4
+ for c in html.chars() {
5
+ match c {
6
+ '>' => write!(writer, "&gt;")?,
7
+ '<' => write!(writer, "&lt;")?,
8
+ '"' => write!(writer, "&quot;")?,
9
+ '&' => write!(writer, "&amp;")?,
10
+ '\'' => write!(writer, "&apos;")?,
11
+ c => writer.write_char(c)?,
12
+ };
13
+ }
14
+
15
+ Ok(())
16
+ }
src/lib.rs ADDED
@@ -0,0 +1,13 @@
1
+ pub mod fragment;
2
+ pub mod html;
3
+ pub mod html_escaping;
4
+ mod numbers;
5
+ mod render;
6
+ mod simple_element;
7
+ mod text_element;
8
+
9
+ pub use self::render::Render;
10
+ pub use fragment::Fragment;
11
+ pub use simple_element::SimpleElement;
12
+ pub use text_element::Raw;
13
+ pub use tide_jsx_impl::{component, html, rsx, view};
src/numbers.rs ADDED
@@ -0,0 +1,27 @@
1
+ use crate::Render;
2
+ use std::fmt::{Result, Write};
3
+
4
+ macro_rules! simple_render_impl {
5
+ ($t:ty) => {
6
+ impl Render for $t {
7
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
8
+ write!(writer, "{}", self)
9
+ }
10
+ }
11
+ };
12
+ }
13
+
14
+ simple_render_impl!(f32);
15
+ simple_render_impl!(f64);
16
+ simple_render_impl!(i128);
17
+ simple_render_impl!(i16);
18
+ simple_render_impl!(i32);
19
+ simple_render_impl!(i64);
20
+ simple_render_impl!(i8);
21
+ simple_render_impl!(isize);
22
+ simple_render_impl!(u128);
23
+ simple_render_impl!(u16);
24
+ simple_render_impl!(u32);
25
+ simple_render_impl!(u64);
26
+ simple_render_impl!(u8);
27
+ simple_render_impl!(usize);
src/render.rs ADDED
@@ -0,0 +1,70 @@
1
+ use std::fmt::{Result, Write};
2
+
3
+ /// Render a component
4
+ ///
5
+ /// This is the underlying mechanism of the `#[component]` macro
6
+ pub trait Render: Sized {
7
+ /// Render the component to a writer.
8
+ /// Make sure you escape html correctly using the `render::html_escaping` module
9
+ fn render_into<W: Write>(self, writer: &mut W) -> Result;
10
+
11
+ /// Render the component to string
12
+ fn render(self) -> String {
13
+ let mut buf = String::new();
14
+ self.render_into(&mut buf).unwrap();
15
+ buf
16
+ }
17
+ }
18
+
19
+ /// Does nothing
20
+ impl Render for () {
21
+ fn render_into<W: Write>(self, _writer: &mut W) -> Result {
22
+ Ok(())
23
+ }
24
+ }
25
+
26
+ /// Renders `A`, then `B`
27
+ impl<A: Render, B: Render> Render for (A, B) {
28
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
29
+ self.0.render_into(writer)?;
30
+ self.1.render_into(writer)
31
+ }
32
+ }
33
+
34
+ /// Renders `A`, then `B`, then `C`
35
+ impl<A: Render, B: Render, C: Render> Render for (A, B, C) {
36
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
37
+ self.0.render_into(writer)?;
38
+ self.1.render_into(writer)?;
39
+ self.2.render_into(writer)
40
+ }
41
+ }
42
+
43
+ /// Renders `T` or nothing
44
+ impl<T: Render> Render for Option<T> {
45
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
46
+ match self {
47
+ None => Ok(()),
48
+ Some(x) => x.render_into(writer),
49
+ }
50
+ }
51
+ }
52
+
53
+ impl<T: Render> Render for Vec<T> {
54
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
55
+ for elem in self {
56
+ elem.render_into(writer)?;
57
+ }
58
+ Ok(())
59
+ }
60
+ }
61
+
62
+ /// Renders `O` or `E`
63
+ impl<O: Render, E: Render> Render for std::result::Result<O, E> {
64
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
65
+ match self {
66
+ Ok(o) => o.render_into(writer),
67
+ Err(e) => e.render_into(writer),
68
+ }
69
+ }
70
+ }
src/simple_element.rs ADDED
@@ -0,0 +1,49 @@
1
+ use crate::html_escaping::escape_html;
2
+ use crate::Render;
3
+ use std::borrow::Cow;
4
+ use std::collections::HashMap;
5
+ use std::fmt::{Result, Write};
6
+
7
+ type Attributes<'a> = Option<HashMap<&'a str, Cow<'a, str>>>;
8
+
9
+ /// Simple HTML element tag
10
+ #[derive(Debug)]
11
+ pub struct SimpleElement<'a, T: Render> {
12
+ /// the HTML tag name, like `html`, `head`, `body`, `link`...
13
+ pub tag_name: &'a str,
14
+ pub attributes: Attributes<'a>,
15
+ pub contents: Option<T>,
16
+ }
17
+
18
+ fn write_attributes<'a, W: Write>(maybe_attributes: Attributes<'a>, writer: &mut W) -> Result {
19
+ match maybe_attributes {
20
+ None => Ok(()),
21
+ Some(mut attributes) => {
22
+ for (key, value) in attributes.drain() {
23
+ write!(writer, " {}=\"", key)?;
24
+ escape_html(&value, writer)?;
25
+ write!(writer, "\"")?;
26
+ }
27
+ Ok(())
28
+ }
29
+ }
30
+ }
31
+
32
+ impl<T: Render> Render for SimpleElement<'_, T> {
33
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
34
+ match self.contents {
35
+ None => {
36
+ write!(writer, "<{}", self.tag_name)?;
37
+ write_attributes(self.attributes, writer)?;
38
+ write!(writer, "/>")
39
+ }
40
+ Some(renderable) => {
41
+ write!(writer, "<{}", self.tag_name)?;
42
+ write_attributes(self.attributes, writer)?;
43
+ write!(writer, ">")?;
44
+ renderable.render_into(writer)?;
45
+ write!(writer, "</{}>", self.tag_name)
46
+ }
47
+ }
48
+ }
49
+ }
src/text_element.rs ADDED
@@ -0,0 +1,65 @@
1
+ use crate::html_escaping::escape_html;
2
+ use crate::Render;
3
+ use std::fmt::{Result, Write};
4
+
5
+ impl Render for String {
6
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
7
+ escape_html(&self, writer)
8
+ }
9
+ }
10
+
11
+ impl Render for &str {
12
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
13
+ escape_html(self, writer)
14
+ }
15
+ }
16
+
17
+ impl Render for std::borrow::Cow<'_, str> {
18
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
19
+ escape_html(&self, writer)
20
+ }
21
+ }
22
+
23
+ /// A raw (unencoded) html string
24
+ #[derive(Debug)]
25
+ pub struct Raw<'s>(&'s str);
26
+
27
+ impl<'s> From<&'s str> for Raw<'s> {
28
+ fn from(s: &'s str) -> Self {
29
+ Raw(s)
30
+ }
31
+ }
32
+
33
+ /// A raw (unencoded) html string
34
+ impl<'s> Render for Raw<'s> {
35
+ fn render_into<W: Write>(self, writer: &mut W) -> Result {
36
+ write!(writer, "{}", self.0)
37
+ }
38
+ }
39
+
40
+ #[cfg(test)]
41
+ mod tests {
42
+ use super::*;
43
+
44
+ #[test]
45
+ fn decodes_html() {
46
+ use pretty_assertions::assert_eq;
47
+ let rendered = "<Hello />".render();
48
+ assert_eq!(rendered, "&lt;Hello /&gt;");
49
+ }
50
+
51
+ #[test]
52
+ fn allows_raw_text() {
53
+ use pretty_assertions::assert_eq;
54
+ let rendered = Raw::from("<Hello />").render();
55
+ assert_eq!(rendered, "<Hello />");
56
+ }
57
+ }
58
+
59
+ /// Creates a raw (unencoded) html string
60
+ #[macro_export]
61
+ macro_rules! raw {
62
+ ($text:expr) => {
63
+ tide_jsx::Raw::from($text)
64
+ };
65
+ }
tests/lib.rs ADDED
@@ -0,0 +1,280 @@
1
+ use pretty_assertions::assert_eq;
2
+ use std::borrow::Cow;
3
+ use tide::StatusCode;
4
+ use tide_jsx::html::HTML5Doctype;
5
+ use tide_jsx::{component, html, raw, rsx, view, Render};
6
+
7
+ #[test]
8
+ fn ui() {
9
+ let t = trybuild::TestCases::new();
10
+ t.compile_fail("tests/ui/fail/*.rs");
11
+ }
12
+
13
+ #[test]
14
+ fn works_with_dashes() {
15
+ use pretty_assertions::assert_eq;
16
+
17
+ let value = html! { <div data-id={"myid"} /> };
18
+ assert_eq!(value, r#"<div data-id="myid"/>"#);
19
+ }
20
+
21
+ #[test]
22
+ fn works_with_raw() {
23
+ let actual = html! {
24
+ <div>{raw!("<Hello />")}</div>
25
+ };
26
+
27
+ assert_eq!(actual, "<div><Hello /></div>");
28
+ }
29
+
30
+ #[test]
31
+ fn works_with_raw_ident() {
32
+ let actual = html! {
33
+ <input r#type={"text"} />
34
+ };
35
+
36
+ assert_eq!(actual, r#"<input type="text"/>"#);
37
+ }
38
+
39
+ #[test]
40
+ fn works_with_keywords() {
41
+ assert_eq!(html! { <input type={"text"} /> }, r#"<input type="text"/>"#);
42
+ assert_eq!(html! { <label for={"me"} /> }, r#"<label for="me"/>"#);
43
+ }
44
+
45
+ #[test]
46
+ fn element_ordering() {
47
+ let actual = html! {
48
+ <ul>
49
+ <li>{"1"}</li>
50
+ <li>{"2"}</li>
51
+ <li>{"3"}</li>
52
+ </ul>
53
+ };
54
+
55
+ assert_eq!(actual, "<ul><li>1</li><li>2</li><li>3</li></ul>");
56
+
57
+ let deep = html! {
58
+ <div>
59
+ <h1>{"A list"}</h1>
60
+ <hr />
61
+ <ul>
62
+ <li>{"1"}</li>
63
+ <li>{"2"}</li>
64
+ <li>{"3"}</li>
65
+ </ul>
66
+ </div>
67
+ };
68
+
69
+ assert_eq!(
70
+ deep,
71
+ "<div><h1>A list</h1><hr/><ul><li>1</li><li>2</li><li>3</li></ul></div>"
72
+ );
73
+ }
74
+
75
+ #[test]
76
+ fn some_none() {
77
+ #[component]
78
+ fn Answer(a: i8) {
79
+ rsx! {
80
+ <>
81
+ {match a {
82
+ 42 => Some("Yes"),
83
+ _ => None,
84
+ }}
85
+ </>
86
+ }
87
+ }
88
+
89
+ assert_eq!(html! { <Answer a={42} /> }, "Yes");
90
+ assert_eq!(html! { <Answer a={44} /> }, "");
91
+ }
92
+
93
+ #[test]
94
+ fn owned_string() {
95
+ #[component]
96
+ fn Welcome<'kind, 'name>(kind: &'kind str, name: &'name str) {
97
+ rsx! {
98
+ <h1 class={format!("{}-title", kind)}>
99
+ {format!("Hello, {}", name)}
100
+ </h1>
101
+ }
102
+ }
103
+
104
+ assert_eq!(
105
+ html! { <Welcome kind={"alien"} name={"Yoda"} /> },
106
+ r#"<h1 class="alien-title">Hello, Yoda</h1>"#
107
+ );
108
+ }
109
+
110
+ #[test]
111
+ fn cow_str() {
112
+ let owned1 = "Borrowed from owned".to_owned();
113
+ let owned2 = "Owned".to_owned();
114
+
115
+ assert_eq!(
116
+ html! {
117
+ <div>
118
+ <p>{Cow::Borrowed("Static")}</p>
119
+ <p>{Cow::<'_, str>::Borrowed(&owned1)}</p>
120
+ <p>{Cow::<'_, str>::Owned(owned2)}</p>
121
+ </div>
122
+ },
123
+ r#"<div><p>Static</p><p>Borrowed from owned</p><p>Owned</p></div>"#,
124
+ );
125
+ }
126
+
127
+ #[test]
128
+ fn number() {
129
+ let num = 42;
130
+
131
+ assert_eq!(html! { <p>{num}</p> }, "<p>42</p>")
132
+ }
133
+
134
+ #[test]
135
+ fn vec() {
136
+ let list = vec!["Mouse", "Rat", "Hamster"];
137
+
138
+ assert_eq!(
139
+ html! {
140
+ <ul>
141
+ {
142
+ list
143
+ .into_iter()
144
+ .map(|text| rsx! { <li>{text}</li> })
145
+ .collect::<Vec<_>>()
146
+ }
147
+ </ul>
148
+ },
149
+ "<ul><li>Mouse</li><li>Rat</li><li>Hamster</li></ul>"
150
+ )
151
+ }
152
+
153
+ #[async_std::test]
154
+ async fn render_view() -> std::io::Result<()> {
155
+ let result = view! { <p>{"hello"}</p> } as tide::Result;
156
+ let mut res = result.unwrap();
157
+ assert_eq!(res.status(), StatusCode::Ok);
158
+ assert_eq!(
159
+ res.header("content-type").unwrap().as_str(),
160
+ tide::http::mime::HTML.to_string()
161
+ );
162
+ assert_eq!(res.take_body().into_string().await.unwrap(), "<p>hello</p>");
163
+ Ok(())
164
+ }
165
+
166
+ mod kaki {
167
+ use crate::other::ExternalPage;
168
+ use crate::{component, html, rsx, HTML5Doctype, Render};
169
+
170
+ // This can be any layout we want
171
+ #[component]
172
+ fn Page<'a, Children: Render>(title: &'a str, children: Children) {
173
+ rsx! {
174
+ <>
175
+ <HTML5Doctype />
176
+ <html>
177
+ <head><title>{title}</title></head>
178
+ <body>
179
+ {children}
180
+ </body>
181
+ </html>
182
+ </>
183
+ }
184
+ }
185
+
186
+ #[test]
187
+ fn test() {
188
+ let actual = html! {
189
+ <Page title={"Home"}>
190
+ {format!("Welcome, {}", "Gal")}
191
+ </Page>
192
+ };
193
+ let expected = concat!(
194
+ "<!DOCTYPE html>",
195
+ "<html>",
196
+ "<head><title>Home</title></head>",
197
+ "<body>",
198
+ "Welcome, Gal",
199
+ "</body>",
200
+ "</html>"
201
+ );
202
+ assert_eq!(actual, expected);
203
+ }
204
+
205
+ #[test]
206
+ fn externals_test() {
207
+ let actual = html! {
208
+ <ExternalPage title={"Home"} subtitle={"Foo"}>
209
+ {format!("Welcome, {}", "Gal")}
210
+ </ExternalPage>
211
+ };
212
+
213
+ let expected = concat!(
214
+ "<!DOCTYPE html>",
215
+ "<html>",
216
+ "<head><title>Home</title></head>",
217
+ "<body>",
218
+ "<h1>Foo</h1>",
219
+ "Welcome, Gal",
220
+ "</body>",
221
+ "</html>"
222
+ );
223
+ assert_eq!(actual, expected);
224
+ }
225
+ }
226
+
227
+ /// ## Other
228
+ ///
229
+ /// Module for testing component visibility when imported from other modules.
230
+
231
+ mod other {
232
+ use crate::{component, rsx, HTML5Doctype, Render};
233
+
234
+ #[component]
235
+ pub fn ExternalPage<'title, 'subtitle, Children: Render>(
236
+ title: &'title str,
237
+ subtitle: &'subtitle str,
238
+ children: Children,
239
+ ) {
240
+ rsx! {
241
+ <>
242
+ <HTML5Doctype />
243
+ <html>
244
+ <head><title>{title}</title></head>
245
+ <body>
246
+ <h1>{subtitle}</h1>
247
+ {children}
248
+ </body>
249
+ </html>
250
+ </>
251
+ }
252
+ }
253
+ }
254
+
255
+ mod integration {
256
+ use crate::view;
257
+ use tide_testing::TideTestingExt;
258
+
259
+ #[async_std::test]
260
+ async fn test_server() -> tide::Result<()> {
261
+ let mut app = tide::new();
262
+ app.at("/").get(|_| async {
263
+ view! {
264
+ <div>
265
+ <p>{"Hello World"}</p>
266
+ </div>
267
+ }
268
+ });
269
+
270
+ assert_eq!(
271
+ app.get("/").recv_string().await?,
272
+ "<div><p>Hello World</p></div>"
273
+ );
274
+ assert_eq!(
275
+ app.post("/missing").await?.status(),
276
+ tide::http::StatusCode::NotFound
277
+ );
278
+ Ok(())
279
+ }
280
+ }
tests/ui/fail/unclosed-tag-complex.rs ADDED
@@ -0,0 +1,14 @@
1
+ use tide_jsx::html;
2
+
3
+ fn main() {
4
+ html! {
5
+ <div>
6
+ <h1>{"A list"}</h1>
7
+ <hr />
8
+ <ul>
9
+ <li>{"1"}</li>
10
+ <li>
11
+ </ul>
12
+ </div>
13
+ };
14
+ }
tests/ui/fail/unclosed-tag-complex.stderr ADDED
@@ -0,0 +1,5 @@
1
+ error: Expected closing tag for: <li>
2
+ --> $DIR/unclosed-tag-complex.rs:11:11
3
+ |
4
+ 11 | </ul>
5
+ | ^^
tests/ui/fail/unclosed-tag.rs ADDED
@@ -0,0 +1,7 @@
1
+ fn main() {
2
+ tide_jsx::html! {
3
+ <ul>
4
+ <li>
5
+ </ul>
6
+ };
7
+ }
tests/ui/fail/unclosed-tag.stderr ADDED
@@ -0,0 +1,5 @@
1
+ error: Expected closing tag for: <li>
2
+ --> tests/ui/fail/unclosed-tag.rs:5:9
3
+ |
4
+ 5 | </ul>
5
+ | ^^
tests/ui/fail/unexpected-attribute.rs ADDED
@@ -0,0 +1,10 @@
1
+ use tide_jsx::{component, html, rsx};
2
+
3
+ #[component]
4
+ fn Heading<'title>(title: &'title str) {
5
+ rsx! { <h1>{title}</h1> }
6
+ }
7
+
8
+ fn main() {
9
+ html! { <Heading t={"Hello world!"} /> };
10
+ }
tests/ui/fail/unexpected-attribute.stderr ADDED
@@ -0,0 +1,7 @@
1
+ error[E0560]: struct `Heading<'_>` has no field named `t`
2
+ --> $DIR/unexpected-attribute.rs:9:22
3
+ |
4
+ 9 | html! { <Heading t={"Hello world!"} /> };
5
+ | ^ `Heading<'_>` does not have this field
6
+ |
7
+ = note: available fields are: `title`