From f08b9b06d36d2e3909151dfeed161a2022c3f741 Mon Sep 17 00:00:00 2001 From: Alexey Dubovskoy Date: Sun, 10 Nov 2024 19:37:34 +0000 Subject: [PATCH 1/2] feat: started wasm migration --- .gitignore | 5 + Cargo.lock | 954 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 + package-lock.json | 207 ++++++---- package.json | 4 + readme.md | 6 + src/aisle.rs | 70 ++++ src/index.ts | 2 + src/lib.rs | 314 +++++++++++++++ src/model.rs | 493 +++++++++++++++++++++++ tests/index.test.ts | 7 +- tsconfig.json | 4 +- 12 files changed, 2003 insertions(+), 76 deletions(-) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/aisle.rs create mode 100644 src/lib.rs create mode 100644 src/model.rs diff --git a/.gitignore b/.gitignore index 8225baa..aea0ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ /node_modules /dist +target/ +.DS_Store +out/ +.idea +.build diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..92daa83 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,954 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi-to-html" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d73c455ae09fa2223a75114789f30ad605e9e297f79537953523366c05995f5f" +dependencies = [ + "regex", + "thiserror", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codesnake" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2205f7f6d3de68ecf4c291c789b3edf07b6569268abd0188819086f71ae42225" + +[[package]] +name = "cooklang" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4b3e629e90bfdeb6bae5551d2c254759868d36d76903c5d76eff0c84c518df0" +dependencies = [ + "bitflags", + "codesnake", + "either", + "emojis", + "enum-map", + "finl_unicode", + "indexmap", + "once_cell", + "pest", + "pest_derive", + "regex", + "serde", + "smallvec", + "strum", + "thiserror", + "toml", + "tracing", + "unicase", + "unicode-width", + "url", + "yansi", +] + +[[package]] +name = "cooklang-wasm" +version = "0.1.0" +dependencies = [ + "ansi-to-html", + "cooklang", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "emojis" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e1f1df1f181f2539bac8bf027d31ca5ffbf9e559e3f2d09413b9107b5c02f4" +dependencies = [ + "phf", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", + "serde", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "finl_unicode" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c970b525906eb37d3940083aa65b95e481fc1857d467d13374e1d925cfc163" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libc" +version = "0.2.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicase" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "url" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d6adeaf --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cooklang-wasm" +version = "0.1.0" +edition = "2021" + +[dependencies] +ansi-to-html = "0.2.1" +cooklang = "0.13.3" +serde_json = "1.0.132" +wasm-bindgen = "0.2.95" + +[lib] +crate-type = ["cdylib", "rlib"] diff --git a/package-lock.json b/package-lock.json index 5aab260..0d0ed0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,16 @@ { "name": "@cooklang/cooklang-ts", - "version": "1.2.6", + "version": "1.2.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cooklang/cooklang-ts", - "version": "1.2.6", + "version": "1.2.7", "license": "MIT", + "dependencies": { + "cooklang-wasm": "file:pkg" + }, "devDependencies": { "@types/jest": "^27.5.0", "@types/node": "^17.0.32", @@ -84,19 +87,33 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.10.tgz", - "integrity": "sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "dependencies": { - "@babel/types": "^7.17.10", - "@jridgewell/gen-mapping": "^0.1.0", + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.17.10", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", @@ -216,10 +233,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -334,9 +360,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", - "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -543,12 +569,13 @@ } }, "node_modules/@babel/types": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.10.tgz", - "integrity": "sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" }, "engines": { @@ -893,37 +920,37 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@sinclair/typebox": { @@ -1568,6 +1595,10 @@ "safe-buffer": "~5.1.1" } }, + "node_modules/cooklang-wasm": { + "resolved": "pkg", + "link": true + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -2019,9 +2050,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -2960,10 +2991,13 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { "version": "1.0.4", @@ -3948,6 +3982,10 @@ "engines": { "node": ">=6" } + }, + "pkg": { + "name": "cooklang-wasm", + "version": "0.1.0" } }, "dependencies": { @@ -4000,14 +4038,27 @@ } }, "@babel/generator": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.10.tgz", - "integrity": "sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "requires": { - "@babel/types": "^7.17.10", - "@jridgewell/gen-mapping": "^0.1.0", + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + } } }, "@babel/helper-compilation-targets": { @@ -4099,10 +4150,16 @@ "@babel/types": "^7.16.7" } }, + "@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true }, "@babel/helper-validator-option": { @@ -4192,9 +4249,9 @@ } }, "@babel/parser": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", - "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -4344,12 +4401,13 @@ } }, "@babel/types": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.10.tgz", - "integrity": "sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" } }, @@ -4620,31 +4678,31 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true }, "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@sinclair/typebox": { @@ -5163,6 +5221,9 @@ "safe-buffer": "~5.1.1" } }, + "cooklang-wasm": { + "version": "file:pkg" + }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -5496,9 +5557,9 @@ } }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "requires": { "has": "^1.0.3" @@ -6214,9 +6275,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, "mkdirp": { diff --git a/package.json b/package.json index 57f1153..0aaeecf 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ ], "scripts": { "build": "tsc", + "build-wasm": "wasm-pack build --target nodejs", "prepare": "npm run build", "watch": "ts-node-dev --respawn --clear --rs src/index.ts", "docs": "node tools/docs.js && typedoc --readme README.md --out docs src/index.ts", @@ -41,5 +42,8 @@ "typedoc": "^0.22.13", "typescript": "^4.6.2", "yaml": "^1.10.2" + }, + "dependencies": { + "cooklang-wasm": "file:pkg" } } diff --git a/readme.md b/readme.md index be8db13..012b1be 100644 --- a/readme.md +++ b/readme.md @@ -56,6 +56,12 @@ The specification can be found [here](https://cooklang.org/docs/spec/). ## GitHub The repository can be found [here](https://github.com/cooklang/cooklang-ts). +## Generating Wasm package + +``` +npm run build-wasm +``` + ## Testing Tests are as found in https://github.com/cooklang/spec/blob/main/tests/canonical.yaml. ``` diff --git a/src/aisle.rs b/src/aisle.rs new file mode 100644 index 0000000..70bebcc --- /dev/null +++ b/src/aisle.rs @@ -0,0 +1,70 @@ +use wasm_bindgen::prelude::*; +use std::collections::HashMap; + +use cooklang::aisle::Category as OriginalAisleCategory; + +#[wasm_bindgen] +pub struct AisleIngredient { + pub name: String, + pub aliases: Vec, +} + +#[wasm_bindgen] +pub struct AisleReverseCategory { + map: HashMap, +} + +#[wasm_bindgen] +impl AisleReverseCategory { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + Self { + map: HashMap::new() + } + } + + pub fn get(&self, key: &str) -> Option { + self.map.get(key).cloned() + } + + pub fn insert(&mut self, key: String, value: String) { + self.map.insert(key, value); + } +} + +#[wasm_bindgen] +pub struct AisleCategory { + pub name: String, + pub ingredients: Vec, +} + +#[wasm_bindgen] +pub struct AisleConf { + pub categories: Vec, + pub cache: AisleReverseCategory, +} + +#[wasm_bindgen] +impl AisleConf { + pub fn category_for(&self, ingredient_name: String) -> Option { + self.cache.get(&ingredient_name) + } +} + +pub fn into_category(original: &OriginalAisleCategory) -> AisleCategory { + let mut ingredients: Vec = Vec::new(); + + original.ingredients.iter().for_each(|i| { + let mut it = i.names.iter(); + + let name = it.next().unwrap().to_string(); + let aliases: Vec = it.map(|v| v.to_string()).collect(); + + ingredients.push(AisleIngredient { name, aliases }); + }); + + AisleCategory { + name: original.name.to_string(), + ingredients, + } +} diff --git a/src/index.ts b/src/index.ts index bd7c487..1eb1991 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,3 +31,5 @@ export { Recipe, Parser }; export * from './Recipe'; export * from './Parser'; export * from './cooklang'; + +export * from "cooklang-wasm"; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7023a9e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,314 @@ +use wasm_bindgen::prelude::*; + +use std::sync::Arc; + +use cooklang::aisle::parse as parse_aisle_config_original; +use cooklang::analysis::parse_events; +use cooklang::parser::PullParser; +use cooklang::{Converter, Extensions}; + +pub mod aisle; +pub mod model; + +use aisle::*; +use model::*; + +#[wasm_bindgen] +pub fn parse_recipe(input: String) -> CooklangRecipe { + let extensions = Extensions::empty(); + let converter = Converter::empty(); + + let mut parser = PullParser::new(&input, extensions); + let parsed = parse_events( + &mut parser, + &input, + extensions, + &converter, + Default::default(), + ) + .unwrap_output(); + + into_simple_recipe(&parsed) +} + +#[wasm_bindgen] +pub fn parse_metadata(input: String) -> CooklangMetadata { + let mut metadata = CooklangMetadata::new(); + let extensions = Extensions::empty(); + let converter = Converter::empty(); + + let parser = PullParser::new(&input, extensions); + + let parsed = parse_events( + parser.into_meta_iter(), + &input, + extensions, + &converter, + Default::default(), + ) + .map(|c| c.metadata.map) + .unwrap_output(); + + // converting IndexMap into HashMap + let _ = &(parsed).iter().for_each(|(key, value)| { + metadata.insert(key.to_string(), value.to_string()); + }); + + metadata +} + +#[wasm_bindgen] +pub fn parse_aisle_config(input: String) -> AisleConf { + let mut categories: Vec = Vec::new(); + let mut cache: AisleReverseCategory = AisleReverseCategory::default(); + + let parsed = parse_aisle_config_original(&input).unwrap(); + + let _ = &(parsed).categories.iter().for_each(|c| { + let category = into_category(c); + + // building cache + category.ingredients.iter().for_each(|i| { + cache.insert(i.name.clone(), category.name.clone()); + + i.aliases.iter().for_each(|a| { + cache.insert(a.to_string(), category.name.clone()); + }); + }); + + categories.push(category); + }); + + AisleConf { categories, cache } +} + +#[wasm_bindgen] +pub fn combine_ingredient_lists(lists: Vec) -> IngredientList { + let mut combined: IngredientList = IngredientList::default(); + + lists + .iter() + .for_each(|l| merge_ingredient_lists(&mut combined, l)); + + combined +} + + +#[cfg(test)] +mod tests { + + #[test] + fn test_parse_recipe() { + use crate::{parse_recipe, Amount, Item, Value}; + + let recipe = parse_recipe( + r#" +a test @step @salt{1%mg} more text +"# + .to_string(), + ); + + assert_eq!( + recipe.steps.into_iter().nth(0).unwrap().items, + vec![ + Item::Text { + value: "a test ".to_string() + }, + Item::Ingredient { + name: "step".to_string(), + amount: None + }, + Item::Text { + value: " ".to_string() + }, + Item::Ingredient { + name: "salt".to_string(), + amount: Some(Amount { + quantity: Value::Number { value: 1.0 }, + units: Some("mg".to_string()) + }) + }, + Item::Text { + value: " more text".to_string() + } + ] + ); + } + + #[test] + fn test_parse_metadata() { + use crate::parse_metadata; + use std::collections::HashMap; + + let metadata = parse_metadata( + r#" +>> source: https://google.com +a test @step @salt{1%mg} more text +"# + .to_string(), + ); + + assert_eq!( + metadata, + HashMap::from([("source".to_string(), "https://google.com".to_string())]) + ); + } + + #[test] + fn test_parse_aisle_config() { + use crate::parse_aisle_config; + + let config = parse_aisle_config( + r#" +[fruit and veg] +apple gala | apples +aubergine +avocado | avocados + +[milk and dairy] +butter +egg | eggs +curd cheese +cheddar cheese +feta + +[dried herbs and spices] +bay leaves +black pepper +cayenne pepper +dried oregano +"# + .to_string(), + ); + + assert_eq!( + config.category_for("bay leaves".to_string()), + Some("dried herbs and spices".to_string()) + ); + + assert_eq!( + config.category_for("eggs".to_string()), + Some("milk and dairy".to_string()) + ); + + assert_eq!( + config.category_for("some weird ingredient".to_string()), + None + ); + } + + #[test] + fn test_combine_ingredient_lists() { + use crate::{combine_ingredient_lists, GroupedQuantityKey, QuantityType, Value}; + use std::collections::HashMap; + + let combined = combine_ingredient_lists(vec![ + HashMap::from([ + ( + "salt".to_string(), + HashMap::from([ + ( + GroupedQuantityKey { + name: "g".to_string(), + unit_type: QuantityType::Number, + }, + Value::Number { value: 5.0 }, + ), + ( + GroupedQuantityKey { + name: "tsp".to_string(), + unit_type: QuantityType::Number, + }, + Value::Number { value: 1.0 }, + ), + ]), + ), + ( + "pepper".to_string(), + HashMap::from([ + ( + GroupedQuantityKey { + name: "mg".to_string(), + unit_type: QuantityType::Number, + }, + Value::Number { value: 5.0 }, + ), + ( + GroupedQuantityKey { + name: "tsp".to_string(), + unit_type: QuantityType::Number, + }, + Value::Number { value: 1.0 }, + ), + ]), + ), + ]), + HashMap::from([( + "salt".to_string(), + HashMap::from([ + ( + GroupedQuantityKey { + name: "kg".to_string(), + unit_type: QuantityType::Number, + }, + Value::Number { value: 0.005 }, + ), + ( + GroupedQuantityKey { + name: "tsp".to_string(), + unit_type: QuantityType::Number, + }, + Value::Number { value: 1.0 }, + ), + ]), + )]), + ]); + + assert_eq!( + *combined.get("salt").unwrap(), + HashMap::from([ + ( + GroupedQuantityKey { + name: "kg".to_string(), + unit_type: QuantityType::Number + }, + Value::Number { value: 0.005 } + ), + ( + GroupedQuantityKey { + name: "tsp".to_string(), + unit_type: QuantityType::Number + }, + Value::Number { value: 2.0 } + ), + ( + GroupedQuantityKey { + name: "g".to_string(), + unit_type: QuantityType::Number + }, + Value::Number { value: 5.0 } + ), + ]) + ); + + assert_eq!( + *combined.get("pepper").unwrap(), + HashMap::from([ + ( + GroupedQuantityKey { + name: "mg".to_string(), + unit_type: QuantityType::Number + }, + Value::Number { value: 5.0 } + ), + ( + GroupedQuantityKey { + name: "tsp".to_string(), + unit_type: QuantityType::Number + }, + Value::Number { value: 1.0 } + ), + ]) + ); + } +} diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..7f62e30 --- /dev/null +++ b/src/model.rs @@ -0,0 +1,493 @@ +use wasm_bindgen::prelude::*; +use std::collections::HashMap; + +use cooklang::model::Item as OriginalItem; +use cooklang::quantity::{ + Quantity as OriginalQuantity, ScalableValue as OriginalScalableValue, Value as OriginalValue, +}; +use cooklang::ScalableRecipe as OriginalRecipe; + +#[wasm_bindgen] +pub struct ItemText { + pub value: String, +} + +#[wasm_bindgen] +pub struct ItemIngredient { + pub name: String, + pub amount: Option, +} + +#[wasm_bindgen] +pub struct ItemCookware { + pub name: String, + pub amount: Option, +} + +#[wasm_bindgen] +pub struct ItemTimer { + pub name: Option, + pub amount: Option, +} + +#[wasm_bindgen] +pub enum ItemType { + Text, + Ingredient, + Cookware, + Timer, +} + +#[wasm_bindgen] +pub struct Item { + pub item_type: ItemType, + pub text: Option, + pub ingredient: Option, + pub cookware: Option, + pub timer: Option, +} + +#[wasm_bindgen] +pub struct CooklangRecipe { + pub metadata: CooklangMetadata, + pub steps: Vec, + pub ingredients: IngredientList, + pub cookware: Vec, +} + +#[wasm_bindgen] +pub struct Step { + pub items: Vec, +} + +#[wasm_bindgen] +pub struct IngredientList { + inner: HashMap +} + +#[wasm_bindgen] +impl IngredientList { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + Self { + inner: HashMap::new() + } + } + + pub fn insert(&mut self, key: String, value: GroupedQuantity) { + self.inner.insert(key, value); + } + + pub fn get(&self, key: &str) -> Option { + self.inner.get(key).cloned() + } +} + +pub(crate) fn into_group_quantity(amount: &Option) -> GroupedQuantity { + // options here: + // - same units: + // - same value type + // - not the same value type + // - different units + // - no units + // - no amount + // + // \ + // |- => 1.2 + // |- => half + // |- <,Text> => pinch + // |- <,Empty> => Some + // + // + // TODO define rules on language spec level??? + let empty_units = "".to_string(); + + let key = if let Some(amount) = amount { + let units = amount.units.as_ref().unwrap_or(&empty_units); + + match &amount.quantity { + Value::Number { .. } => GroupedQuantityKey { + name: units.to_string(), + unit_type: QuantityType::Number, + }, + Value::Range { .. } => GroupedQuantityKey { + name: units.to_string(), + unit_type: QuantityType::Range, + }, + Value::Text { .. } => GroupedQuantityKey { + name: units.to_string(), + unit_type: QuantityType::Text, + }, + Value::Empty => GroupedQuantityKey { + name: units.to_string(), + unit_type: QuantityType::Empty, + }, + } + } else { + GroupedQuantityKey { + name: empty_units, + unit_type: QuantityType::Empty, + } + }; + + let value = if let Some(amount) = amount { + amount.quantity.clone() + } else { + Value::Empty + }; + + GroupedQuantity::from([(key, value)]) +} + +#[wasm_bindgen] +pub enum QuantityType { + Number, + Range, // how to combine ranges? + Text, + Empty, +} + +#[wasm_bindgen] +pub struct GroupedQuantityKey { + pub name: String, + pub unit_type: QuantityType, +} + +#[wasm_bindgen] +pub struct GroupedQuantity { + inner: HashMap +} + +#[wasm_bindgen] +impl GroupedQuantity { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + Self { + inner: HashMap::new() + } + } + + pub fn insert(&mut self, key: GroupedQuantityKey, value: Value) { + self.inner.insert(key, value); + } + + pub fn get(&self, key: &GroupedQuantityKey) -> Option { + self.inner.get(key).cloned() + } +} + +// Update the from implementation +impl From<[(GroupedQuantityKey, Value); 1]> for GroupedQuantity { + fn from(arr: [(GroupedQuantityKey, Value); 1]) -> Self { + let mut map = HashMap::new(); + map.insert(arr[0].0, arr[0].1); + Self { inner: map } + } +} + +#[wasm_bindgen] +pub struct Amount { + pub(crate) quantity: Value, + pub(crate) units: Option, +} + +#[wasm_bindgen] +#[derive(Clone)] +pub enum ValueType { + Number, + Range, + Text, + Empty, +} + +#[wasm_bindgen] +#[derive(Clone)] +pub struct Value { + pub value_type: ValueType, + pub number_value: Option, + pub range_start: Option, + pub range_end: Option, + pub text_value: Option, +} + +#[wasm_bindgen] +#[derive(Default)] +pub struct CooklangMetadata { + inner: HashMap, +} + +#[wasm_bindgen] +impl CooklangMetadata { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + Self { + inner: HashMap::new() + } + } + + pub fn insert(&mut self, key: String, value: String) { + self.inner.insert(key, value); + } + + pub fn get(&self, key: &str) -> Option { + self.inner.get(key).cloned() + } +} + +trait Amountable { + fn extract_amount(&self) -> Amount; +} + +impl Amountable for OriginalQuantity { + fn extract_amount(&self) -> Amount { + let quantity = extract_quantity(&self.value); + + let units = self.unit().as_ref().map(|u| u.to_string()); + + Amount { quantity, units } + } +} + +impl Amountable for OriginalScalableValue { + fn extract_amount(&self) -> Amount { + let quantity = extract_quantity(self); + + Amount { + quantity, + units: None, + } + } +} + +fn extract_quantity(value: &OriginalScalableValue) -> Value { + match value { + OriginalScalableValue::Fixed(value) => extract_value(value), + OriginalScalableValue::Linear(value) => extract_value(value), + OriginalScalableValue::ByServings(values) => extract_value(values.first().unwrap()), + } +} + +fn extract_value(value: &OriginalValue) -> Value { + match value { + OriginalValue::Number(num) => Value { + value_type: ValueType::Number, + number_value: Some(num.value()), + range_start: None, + range_end: None, + text_value: None, + }, + OriginalValue::Range { start, end } => Value { + value_type: ValueType::Range, + number_value: None, + range_start: Some(start.value()), + range_end: Some(end.value()), + text_value: None, + }, + OriginalValue::Text(value) => Value { + value_type: ValueType::Text, + number_value: None, + range_start: None, + range_end: None, + text_value: Some(value.to_string()), + }, + } +} + +// I(dubadub) haven't found a way to export these methods with mutable argument +pub fn add_to_ingredient_list( + list: &mut IngredientList, + name: &String, + quantity_to_add: &GroupedQuantity, +) { + if let Some(quantity) = list.inner.get_mut(name) { + merge_grouped_quantities(quantity, quantity_to_add); + } else { + list.inner.insert(name.to_string(), quantity_to_add.clone()); + } +} + +// O(n2)? find a better way +pub fn merge_ingredient_lists(left: &mut IngredientList, right: &IngredientList) { + right.inner + .iter() + .for_each(|(ingredient_name, grouped_quantity)| { + let quantity = left.inner + .entry(ingredient_name.to_string()) + .or_insert(GroupedQuantity::default()); + + merge_grouped_quantities(quantity, grouped_quantity); + }); +} + +// I(dubadub) haven't found a way to export these methods with mutable argument +// Right should be always smaller? +pub(crate) fn merge_grouped_quantities(left: &mut GroupedQuantity, right: &GroupedQuantity) { + // options here: + // - same units: + // - same value type + // - not the same value type + // - different units + // - no units + // - no amount + // + // \ + // |- => 1.2 litre + // |- => half litre + // |- <,Text> => pinch + // |- <,Empty> => Some + // + // + // TODO define rules on language spec level + + right.iter().for_each(|(key, value)| { + left + .entry(key.clone()) // isn't really necessary? + .and_modify(|v| { + match key.unit_type { + QuantityType::Number => { + let Value::Number { value: assignable } = value else { panic!("Unexpected type") }; + let Value::Number { value: stored } = v else { panic!("Unexpected type") }; + + *stored += assignable + }, + QuantityType::Range => { + let Value::Range { start, end } = value else { panic!("Unexpected type") }; + let Value::Range { start: s, end: e } = v else { panic!("Unexpected type") }; + + // is it even correct? + *s += start; + *e += end; + }, + QuantityType::Text => { + let Value::Text { value: ref assignable } = value else { panic!("Unexpected type") }; + let Value::Text { value: stored } = v else { panic!("Unexpected type") }; + + *stored += assignable; + }, + QuantityType::Empty => {}, // nothing is required to do, Some + Some = Some + + } + }) + .or_insert(value.clone()); + }); +} + +pub(crate) fn into_item(item: &OriginalItem, recipe: &OriginalRecipe) -> Item { + match item { + OriginalItem::Text { value } => Item { + item_type: ItemType::Text, + text: Some(ItemText { + value: value.to_string(), + }), + ingredient: None, + cookware: None, + timer: None, + }, + OriginalItem::Ingredient { index } => { + let ingredient = &recipe.ingredients[*index]; + Item { + item_type: ItemType::Ingredient, + text: None, + ingredient: Some(ItemIngredient { + name: ingredient.name.clone(), + amount: ingredient.quantity.as_ref().map(|q| q.extract_amount()), + }), + cookware: None, + timer: None, + } + } + OriginalItem::Cookware { index } => { + let cookware = &recipe.cookware[*index]; + Item { + item_type: ItemType::Cookware, + text: None, + ingredient: None, + cookware: Some(ItemCookware { + name: cookware.name.clone(), + amount: cookware.quantity.as_ref().map(|q| q.extract_amount()), + }), + timer: None, + } + } + OriginalItem::Timer { index } => { + let timer = &recipe.timers[*index]; + Item { + item_type: ItemType::Timer, + text: None, + ingredient: None, + cookware: None, + timer: Some(ItemTimer { + name: timer.name.clone(), + amount: timer.quantity.as_ref().map(|q| q.extract_amount()), + }), + } + } + OriginalItem::InlineQuantity { index: _ } => Item { + item_type: ItemType::Text, + text: Some(ItemText { + value: "".to_string(), + }), + ingredient: None, + cookware: None, + timer: None, + }, + } +} + +pub(crate) fn into_simple_recipe(recipe: &OriginalRecipe) -> CooklangRecipe { + let mut metadata = CooklangMetadata::new(); + let mut steps: Vec = Vec::new(); + let mut ingredients: IngredientList = IngredientList::new(); + let mut cookware: Vec = Vec::new(); + let mut items: Vec = Vec::new(); + + recipe.sections.iter().for_each(|section| { + section.content.iter().for_each(|content| { + if let cooklang::Content::Step(step) = content { + step.items.iter().for_each(|i| { + let item = into_item(i, recipe); + + match item { + Item { + item_type: ItemType::Ingredient, + ingredient: Some(ref ingredient), + .. + } => { + let quantity = into_group_quantity(&ingredient.amount); + + add_to_ingredient_list(&mut ingredients, &ingredient.name, &quantity); + } + Item { + item_type: ItemType::Cookware, + cookware: Some(ref cookware), + .. + } => { + cookware.push(cookware.clone()); + } + // don't need anything if timer or text + _ => (), + }; + items.push(item); + }); + // TODO: think how to make it faster as we probably + // can switch items content directly into the step object without cloning it + steps.push(Step { + items: items.clone(), + }); + + items.clear(); + } + }); + }); + + recipe.metadata.map.iter().for_each(|(key, value)| { + metadata.insert(key.to_string(), value.to_string()); + }); + + CooklangRecipe { + metadata, + steps, + ingredients, + cookware, + } +} diff --git a/tests/index.test.ts b/tests/index.test.ts index 61e1e22..ba9ee14 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import * as yaml from 'yaml'; import { Parser } from '../src/index'; +import { State } from '../src/index'; import { Step } from '../src/cooklang'; const parser = new Parser(); @@ -31,7 +32,11 @@ testFiles.forEach((testFile) => { metadata: parsed.metadata, }; - expect(expected).toStrictEqual(actual); + const state = new State(); + const { value, error } = state.parse_full(source, false); + + + expect(value).toStrictEqual(result); }); }); }); diff --git a/tsconfig.json b/tsconfig.json index 7bbeea7..27e5ccf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -21,7 +21,7 @@ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "esnext", /* Specify what module code is generated. */ "rootDir": "./src", /* Specify the root folder within your source files. */ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ From 4c5df3d23332d605b9c7d375b28aefb0129df225 Mon Sep 17 00:00:00 2001 From: Alexey Dubovskoy Date: Sun, 22 Dec 2024 22:10:56 +0000 Subject: [PATCH 2/2] feat: first working version based on binidngs --- Cargo.lock | 437 +++++++++++++++++++++++++++++- Cargo.toml | 8 +- src/index.ts | 7 - src/lib.rs | 637 +++++++++++++++++++++++++------------------- src/model.rs | 493 ---------------------------------- tests/index.test.ts | 49 +++- 6 files changed, 821 insertions(+), 810 deletions(-) delete mode 100644 src/model.rs diff --git a/Cargo.lock b/Cargo.lock index 92daa83..08301f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,13 +12,74 @@ dependencies = [ ] [[package]] -name = "ansi-to-html" +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73c455ae09fa2223a75114789f30ad605e9e297f79537953523366c05995f5f" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" dependencies = [ - "regex", - "thiserror", + "nom", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", ] [[package]] @@ -45,12 +106,62 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "codesnake" version = "0.2.1" @@ -59,9 +170,7 @@ checksum = "2205f7f6d3de68ecf4c291c789b3edf07b6569268abd0188819086f71ae42225" [[package]] name = "cooklang" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4b3e629e90bfdeb6bae5551d2c254759868d36d76903c5d76eff0c84c518df0" +version = "0.14.0" dependencies = [ "bitflags", "codesnake", @@ -69,16 +178,16 @@ dependencies = [ "emojis", "enum-map", "finl_unicode", - "indexmap", "once_cell", "pest", "pest_derive", "regex", "serde", + "serde_yaml", "smallvec", "strum", "thiserror", - "toml", + "toml 0.8.19", "tracing", "unicase", "unicode-width", @@ -86,13 +195,23 @@ dependencies = [ "yansi", ] +[[package]] +name = "cooklang-bindings" +version = "0.14.2" +dependencies = [ + "anyhow", + "clap_derive", + "cooklang", + "uniffi", +] + [[package]] name = "cooklang-wasm" version = "0.1.0" dependencies = [ - "ansi-to-html", - "cooklang", - "serde_json", + "cooklang-bindings", + "serde", + "serde-wasm-bindgen", "wasm-bindgen", ] @@ -193,6 +312,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -203,6 +331,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "hashbrown" version = "0.15.1" @@ -362,7 +507,6 @@ checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", - "serde", ] [[package]] @@ -371,6 +515,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.162" @@ -395,12 +548,50 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -476,6 +667,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "proc-macro2" version = "1.0.89" @@ -535,6 +732,35 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +dependencies = [ + "serde", +] + [[package]] name = "serde" version = "1.0.214" @@ -544,6 +770,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.214" @@ -576,6 +813,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha2" version = "0.10.8" @@ -599,12 +849,24 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strum" version = "0.26.3" @@ -649,6 +911,15 @@ dependencies = [ "syn", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -679,6 +950,15 @@ dependencies = [ "zerovec", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -774,6 +1054,128 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "uniffi" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cb08c58c7ed7033150132febe696bef553f891b1ede57424b40d87a89e3c170" +dependencies = [ + "anyhow", + "cargo_metadata", + "uniffi_bindgen", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cade167af943e189a55020eda2c314681e223f1e42aca7c4e52614c2b627698f" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err", + "glob", + "goblin", + "heck", + "once_cell", + "paste", + "serde", + "textwrap", + "toml 0.5.11", + "uniffi_meta", + "uniffi_udl", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "uniffi_core" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f" +dependencies = [ + "anyhow", + "bytes", + "log", + "once_cell", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c65a5b12ec544ef136693af8759fb9d11aefce740fb76916721e876639033b" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn", + "toml 0.5.11", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a74ed96c26882dac1ca9b93ca23c827e284bacbd7ec23c6f0b0372f747d59e4" +dependencies = [ + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6f984f0781f892cc864a62c3a5c60361b1ccbd68e538e6c9fbced5d82268ac" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037820a4cfc4422db1eaa82f291a3863c92c7d1789dc513489c36223f9b4cdfc" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.3" @@ -859,6 +1261,15 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom", +] + [[package]] name = "winnow" version = "0.6.20" diff --git a/Cargo.toml b/Cargo.toml index d6adeaf..0854a14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -ansi-to-html = "0.2.1" -cooklang = "0.13.3" -serde_json = "1.0.132" -wasm-bindgen = "0.2.95" +cooklang-bindings = { path = "../cooklang-rs/bindings" } +serde = { version = "1.0", features = ["derive"] } +wasm-bindgen = "0.2" +serde-wasm-bindgen = "0.5" [lib] crate-type = ["cdylib", "rlib"] diff --git a/src/index.ts b/src/index.ts index 1eb1991..086f5ce 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,13 +23,6 @@ export function getImageURL(name: string, options?: ImageURLOptions) { return name + (options.step ? '.' + options.step : '') + '.' + (options.extension || 'png'); } -import Recipe from './Recipe'; -import Parser from './Parser'; -export { Recipe, Parser }; - -export * from './Recipe'; -export * from './Parser'; -export * from './cooklang'; export * from "cooklang-wasm"; diff --git a/src/lib.rs b/src/lib.rs index 7023a9e..7e09e47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,314 +1,389 @@ use wasm_bindgen::prelude::*; +use serde::Serialize; -use std::sync::Arc; +#[wasm_bindgen] +pub fn parse_recipe(recipe: &str) -> CooklangRecipe { + cooklang_bindings::parse_recipe(recipe.to_string()).into() +} + +#[wasm_bindgen] +#[derive(Clone, Serialize)] +pub struct CooklangRecipe { + #[wasm_bindgen(skip)] + pub metadata: Vec<(String, String)>, + #[wasm_bindgen(skip)] + pub sections: Vec
, + #[wasm_bindgen(skip)] + pub ingredients: Vec, + #[wasm_bindgen(skip)] + pub cookware: Vec, + #[wasm_bindgen(skip)] + pub timers: Vec, +} -use cooklang::aisle::parse as parse_aisle_config_original; -use cooklang::analysis::parse_events; -use cooklang::parser::PullParser; -use cooklang::{Converter, Extensions}; +// Add getter methods for the fields +#[wasm_bindgen] +impl CooklangRecipe { + #[wasm_bindgen(getter)] + pub fn metadata(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.metadata).unwrap() + } -pub mod aisle; -pub mod model; + #[wasm_bindgen(getter)] + pub fn sections(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.sections).unwrap() + } -use aisle::*; -use model::*; + #[wasm_bindgen(getter)] + pub fn ingredients(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.ingredients).unwrap() + } -#[wasm_bindgen] -pub fn parse_recipe(input: String) -> CooklangRecipe { - let extensions = Extensions::empty(); - let converter = Converter::empty(); - - let mut parser = PullParser::new(&input, extensions); - let parsed = parse_events( - &mut parser, - &input, - extensions, - &converter, - Default::default(), - ) - .unwrap_output(); - - into_simple_recipe(&parsed) + #[wasm_bindgen(getter)] + pub fn cookware(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.cookware).unwrap() + } + + #[wasm_bindgen(getter)] + pub fn timers(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.timers).unwrap() + } } +pub type ComponentRef = u32; + #[wasm_bindgen] -pub fn parse_metadata(input: String) -> CooklangMetadata { - let mut metadata = CooklangMetadata::new(); - let extensions = Extensions::empty(); - let converter = Converter::empty(); - - let parser = PullParser::new(&input, extensions); - - let parsed = parse_events( - parser.into_meta_iter(), - &input, - extensions, - &converter, - Default::default(), - ) - .map(|c| c.metadata.map) - .unwrap_output(); - - // converting IndexMap into HashMap - let _ = &(parsed).iter().for_each(|(key, value)| { - metadata.insert(key.to_string(), value.to_string()); - }); - - metadata +#[derive(Clone, Serialize)] +pub struct Section { + #[wasm_bindgen(skip)] + pub title: Option, + #[wasm_bindgen(skip)] + pub blocks: Vec, + #[wasm_bindgen(skip)] + pub ingredient_refs: Vec, + #[wasm_bindgen(skip)] + pub cookware_refs: Vec, + #[wasm_bindgen(skip)] + pub timer_refs: Vec, } +// Add getters for Section #[wasm_bindgen] -pub fn parse_aisle_config(input: String) -> AisleConf { - let mut categories: Vec = Vec::new(); - let mut cache: AisleReverseCategory = AisleReverseCategory::default(); +impl Section { + #[wasm_bindgen(getter)] + pub fn title(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.title).unwrap() + } + + #[wasm_bindgen(getter)] + pub fn blocks(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.blocks).unwrap() + } + + #[wasm_bindgen(getter)] + pub fn ingredient_refs(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.ingredient_refs).unwrap() + } + + #[wasm_bindgen(getter)] + pub fn cookware_refs(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.cookware_refs).unwrap() + } - let parsed = parse_aisle_config_original(&input).unwrap(); + #[wasm_bindgen(getter)] + pub fn timer_refs(&self) -> JsValue { + serde_wasm_bindgen::to_value(&self.timer_refs).unwrap() + } +} + +#[derive(Clone, Serialize)] +pub struct Block { + pub block_type: String, + pub step: Option, + pub note: Option, +} - let _ = &(parsed).categories.iter().for_each(|c| { - let category = into_category(c); +#[derive(Clone, Serialize)] +pub struct Step { + pub items: Vec, + pub ingredient_refs: Vec, + pub cookware_refs: Vec, + pub timer_refs: Vec, +} - // building cache - category.ingredients.iter().for_each(|i| { - cache.insert(i.name.clone(), category.name.clone()); +#[derive(Clone, Serialize)] +pub struct BlockNote { + pub text: String, +} - i.aliases.iter().for_each(|a| { - cache.insert(a.to_string(), category.name.clone()); - }); - }); +#[derive(Clone, Serialize)] +pub struct Ingredient { + pub name: String, + pub amount: Option, + pub descriptor: Option, +} - categories.push(category); - }); +#[derive(Clone, Serialize)] +pub struct Cookware { + pub name: String, + pub amount: Option, +} - AisleConf { categories, cache } +#[derive(Clone, Serialize)] +pub struct Timer { + pub name: Option, + pub amount: Option, } -#[wasm_bindgen] -pub fn combine_ingredient_lists(lists: Vec) -> IngredientList { - let mut combined: IngredientList = IngredientList::default(); +#[derive(Clone, Serialize)] +pub struct Item { + pub item_type: String, + pub text_value: Option, + pub ref_index: Option, +} + +#[derive(Clone, Serialize)] +pub struct Amount { + pub(crate) quantity: Value, + pub(crate) units: Option, +} + +#[derive(Clone, Serialize)] +pub struct Value { + pub value_type: String, + pub number_value: Option, + pub range_start: Option, + pub range_end: Option, + pub text_value: Option, +} - lists - .iter() - .for_each(|l| merge_ingredient_lists(&mut combined, l)); +// Helper methods for constructing these types +impl Block { + pub fn step(step: Step) -> Self { + Block { + block_type: "step".to_string(), + step: Some(step), + note: None, + } + } - combined + pub fn note(note: BlockNote) -> Self { + Block { + block_type: "note".to_string(), + step: None, + note: Some(note), + } + } } +impl Item { + pub fn text(value: String) -> Self { + Item { + item_type: "text".to_string(), + text_value: Some(value), + ref_index: None, + } + } -#[cfg(test)] -mod tests { - - #[test] - fn test_parse_recipe() { - use crate::{parse_recipe, Amount, Item, Value}; - - let recipe = parse_recipe( - r#" -a test @step @salt{1%mg} more text -"# - .to_string(), - ); - - assert_eq!( - recipe.steps.into_iter().nth(0).unwrap().items, - vec![ - Item::Text { - value: "a test ".to_string() - }, - Item::Ingredient { - name: "step".to_string(), - amount: None - }, - Item::Text { - value: " ".to_string() - }, - Item::Ingredient { - name: "salt".to_string(), - amount: Some(Amount { - quantity: Value::Number { value: 1.0 }, - units: Some("mg".to_string()) - }) - }, - Item::Text { - value: " more text".to_string() - } - ] - ); + pub fn ingredient_ref(index: usize) -> Self { + Item { + item_type: "ingredient_ref".to_string(), + text_value: None, + ref_index: Some(index), + } } - #[test] - fn test_parse_metadata() { - use crate::parse_metadata; - use std::collections::HashMap; - - let metadata = parse_metadata( - r#" ->> source: https://google.com -a test @step @salt{1%mg} more text -"# - .to_string(), - ); - - assert_eq!( - metadata, - HashMap::from([("source".to_string(), "https://google.com".to_string())]) - ); + pub fn cookware_ref(index: usize) -> Self { + Item { + item_type: "cookware_ref".to_string(), + text_value: None, + ref_index: Some(index), + } } - #[test] - fn test_parse_aisle_config() { - use crate::parse_aisle_config; - - let config = parse_aisle_config( - r#" -[fruit and veg] -apple gala | apples -aubergine -avocado | avocados - -[milk and dairy] -butter -egg | eggs -curd cheese -cheddar cheese -feta - -[dried herbs and spices] -bay leaves -black pepper -cayenne pepper -dried oregano -"# - .to_string(), - ); - - assert_eq!( - config.category_for("bay leaves".to_string()), - Some("dried herbs and spices".to_string()) - ); - - assert_eq!( - config.category_for("eggs".to_string()), - Some("milk and dairy".to_string()) - ); - - assert_eq!( - config.category_for("some weird ingredient".to_string()), - None - ); + pub fn timer_ref(index: usize) -> Self { + Item { + item_type: "timer_ref".to_string(), + text_value: None, + ref_index: Some(index), + } } +} + +impl Value { + pub fn number(value: f64) -> Self { + Value { + value_type: "number".to_string(), + number_value: Some(value), + range_start: None, + range_end: None, + text_value: None, + } + } + + pub fn range(start: f64, end: f64) -> Self { + Value { + value_type: "range".to_string(), + number_value: None, + range_start: Some(start), + range_end: Some(end), + text_value: None, + } + } + + pub fn text(value: String) -> Self { + Value { + value_type: "text".to_string(), + number_value: None, + range_start: None, + range_end: None, + text_value: Some(value), + } + } + + pub fn empty() -> Self { + Value { + value_type: "empty".to_string(), + number_value: None, + range_start: None, + range_end: None, + text_value: None, + } + } +} + + +impl From for CooklangRecipe { + fn from(recipe: cooklang_bindings::model::CooklangRecipe) -> Self { + CooklangRecipe { + metadata: recipe.metadata.into_iter().collect(), + sections: recipe.sections.into_iter().map(|s| s.into()).collect(), + ingredients: recipe.ingredients.into_iter().map(|i| i.into()).collect(), + cookware: recipe.cookware.into_iter().map(|c| c.into()).collect(), + timers: recipe.timers.into_iter().map(|t| t.into()).collect(), + } + } +} + +impl From for Section { + fn from(section: cooklang_bindings::model::Section) -> Self { + Section { + title: section.title, + blocks: section.blocks.into_iter().map(|b| b.into()).collect(), + ingredient_refs: section.ingredient_refs, + cookware_refs: section.cookware_refs, + timer_refs: section.timer_refs, + } + } +} + +impl From for Block { + fn from(block: cooklang_bindings::model::Block) -> Self { + match block { + cooklang_bindings::model::Block::StepBlock(step) => Block::step(step.into()), + cooklang_bindings::model::Block::NoteBlock(text) => Block::note(text.into()), + } + } +} + +impl From for Step { + fn from(step: cooklang_bindings::model::Step) -> Self { + Step { + items: step.items.into_iter().map(|i| i.into()).collect(), + ingredient_refs: step.ingredient_refs, + cookware_refs: step.cookware_refs, + timer_refs: step.timer_refs, + } + } +} + +impl From for BlockNote { + fn from(note: cooklang_bindings::model::BlockNote) -> Self { + BlockNote { + text: note.text, + } + } +} + +impl From for Ingredient { + fn from(ingredient: cooklang_bindings::model::Ingredient) -> Self { + Ingredient { + name: ingredient.name, + amount: ingredient.amount.map(|a| a.into()), + descriptor: ingredient.descriptor, + } + } +} + +impl From for Cookware { + fn from(cookware: cooklang_bindings::model::Cookware) -> Self { + Cookware { + name: cookware.name, + amount: cookware.amount.map(|a| a.into()), + } + } +} + +impl From for Timer { + fn from(timer: cooklang_bindings::model::Timer) -> Self { + Timer { + name: timer.name, + amount: timer.amount.map(|a| a.into()), + } + } +} + +impl From for Item { + fn from(item: cooklang_bindings::model::Item) -> Self { + match item { + cooklang_bindings::model::Item::Text { value } => Item::text(value), + cooklang_bindings::model::Item::IngredientRef { index } => { + Item::ingredient_ref(index.try_into().unwrap()) + }, + cooklang_bindings::model::Item::CookwareRef { index } => { + Item::cookware_ref(index.try_into().unwrap()) + }, + cooklang_bindings::model::Item::TimerRef { index } => { + Item::timer_ref(index.try_into().unwrap()) + }, + } + } +} + +impl From for Amount { + fn from(amount: cooklang_bindings::model::Amount) -> Self { + Amount { + quantity: amount.quantity.into(), + units: amount.units.clone(), + } + } +} - #[test] - fn test_combine_ingredient_lists() { - use crate::{combine_ingredient_lists, GroupedQuantityKey, QuantityType, Value}; - use std::collections::HashMap; - - let combined = combine_ingredient_lists(vec![ - HashMap::from([ - ( - "salt".to_string(), - HashMap::from([ - ( - GroupedQuantityKey { - name: "g".to_string(), - unit_type: QuantityType::Number, - }, - Value::Number { value: 5.0 }, - ), - ( - GroupedQuantityKey { - name: "tsp".to_string(), - unit_type: QuantityType::Number, - }, - Value::Number { value: 1.0 }, - ), - ]), - ), - ( - "pepper".to_string(), - HashMap::from([ - ( - GroupedQuantityKey { - name: "mg".to_string(), - unit_type: QuantityType::Number, - }, - Value::Number { value: 5.0 }, - ), - ( - GroupedQuantityKey { - name: "tsp".to_string(), - unit_type: QuantityType::Number, - }, - Value::Number { value: 1.0 }, - ), - ]), - ), - ]), - HashMap::from([( - "salt".to_string(), - HashMap::from([ - ( - GroupedQuantityKey { - name: "kg".to_string(), - unit_type: QuantityType::Number, - }, - Value::Number { value: 0.005 }, - ), - ( - GroupedQuantityKey { - name: "tsp".to_string(), - unit_type: QuantityType::Number, - }, - Value::Number { value: 1.0 }, - ), - ]), - )]), - ]); - - assert_eq!( - *combined.get("salt").unwrap(), - HashMap::from([ - ( - GroupedQuantityKey { - name: "kg".to_string(), - unit_type: QuantityType::Number - }, - Value::Number { value: 0.005 } - ), - ( - GroupedQuantityKey { - name: "tsp".to_string(), - unit_type: QuantityType::Number - }, - Value::Number { value: 2.0 } - ), - ( - GroupedQuantityKey { - name: "g".to_string(), - unit_type: QuantityType::Number - }, - Value::Number { value: 5.0 } - ), - ]) - ); - - assert_eq!( - *combined.get("pepper").unwrap(), - HashMap::from([ - ( - GroupedQuantityKey { - name: "mg".to_string(), - unit_type: QuantityType::Number - }, - Value::Number { value: 5.0 } - ), - ( - GroupedQuantityKey { - name: "tsp".to_string(), - unit_type: QuantityType::Number - }, - Value::Number { value: 1.0 } - ), - ]) - ); +impl From for Value { + fn from(value: cooklang_bindings::model::Value) -> Self { + match value { + cooklang_bindings::model::Value::Number { value } => Value::number(value), + cooklang_bindings::model::Value::Range { start, end } => Value { + value_type: "range".to_string(), + number_value: None, + range_start: Some(start), + range_end: Some(end), + text_value: None, + }, + cooklang_bindings::model::Value::Text { value } => Value { + value_type: "text".to_string(), + number_value: None, + range_start: None, + range_end: None, + text_value: Some(value), + }, + cooklang_bindings::model::Value::Empty => Value { + value_type: "empty".to_string(), + number_value: None, + range_start: None, + range_end: None, + text_value: None, + }, + } } } diff --git a/src/model.rs b/src/model.rs deleted file mode 100644 index 7f62e30..0000000 --- a/src/model.rs +++ /dev/null @@ -1,493 +0,0 @@ -use wasm_bindgen::prelude::*; -use std::collections::HashMap; - -use cooklang::model::Item as OriginalItem; -use cooklang::quantity::{ - Quantity as OriginalQuantity, ScalableValue as OriginalScalableValue, Value as OriginalValue, -}; -use cooklang::ScalableRecipe as OriginalRecipe; - -#[wasm_bindgen] -pub struct ItemText { - pub value: String, -} - -#[wasm_bindgen] -pub struct ItemIngredient { - pub name: String, - pub amount: Option, -} - -#[wasm_bindgen] -pub struct ItemCookware { - pub name: String, - pub amount: Option, -} - -#[wasm_bindgen] -pub struct ItemTimer { - pub name: Option, - pub amount: Option, -} - -#[wasm_bindgen] -pub enum ItemType { - Text, - Ingredient, - Cookware, - Timer, -} - -#[wasm_bindgen] -pub struct Item { - pub item_type: ItemType, - pub text: Option, - pub ingredient: Option, - pub cookware: Option, - pub timer: Option, -} - -#[wasm_bindgen] -pub struct CooklangRecipe { - pub metadata: CooklangMetadata, - pub steps: Vec, - pub ingredients: IngredientList, - pub cookware: Vec, -} - -#[wasm_bindgen] -pub struct Step { - pub items: Vec, -} - -#[wasm_bindgen] -pub struct IngredientList { - inner: HashMap -} - -#[wasm_bindgen] -impl IngredientList { - #[wasm_bindgen(constructor)] - pub fn new() -> Self { - Self { - inner: HashMap::new() - } - } - - pub fn insert(&mut self, key: String, value: GroupedQuantity) { - self.inner.insert(key, value); - } - - pub fn get(&self, key: &str) -> Option { - self.inner.get(key).cloned() - } -} - -pub(crate) fn into_group_quantity(amount: &Option) -> GroupedQuantity { - // options here: - // - same units: - // - same value type - // - not the same value type - // - different units - // - no units - // - no amount - // - // \ - // |- => 1.2 - // |- => half - // |- <,Text> => pinch - // |- <,Empty> => Some - // - // - // TODO define rules on language spec level??? - let empty_units = "".to_string(); - - let key = if let Some(amount) = amount { - let units = amount.units.as_ref().unwrap_or(&empty_units); - - match &amount.quantity { - Value::Number { .. } => GroupedQuantityKey { - name: units.to_string(), - unit_type: QuantityType::Number, - }, - Value::Range { .. } => GroupedQuantityKey { - name: units.to_string(), - unit_type: QuantityType::Range, - }, - Value::Text { .. } => GroupedQuantityKey { - name: units.to_string(), - unit_type: QuantityType::Text, - }, - Value::Empty => GroupedQuantityKey { - name: units.to_string(), - unit_type: QuantityType::Empty, - }, - } - } else { - GroupedQuantityKey { - name: empty_units, - unit_type: QuantityType::Empty, - } - }; - - let value = if let Some(amount) = amount { - amount.quantity.clone() - } else { - Value::Empty - }; - - GroupedQuantity::from([(key, value)]) -} - -#[wasm_bindgen] -pub enum QuantityType { - Number, - Range, // how to combine ranges? - Text, - Empty, -} - -#[wasm_bindgen] -pub struct GroupedQuantityKey { - pub name: String, - pub unit_type: QuantityType, -} - -#[wasm_bindgen] -pub struct GroupedQuantity { - inner: HashMap -} - -#[wasm_bindgen] -impl GroupedQuantity { - #[wasm_bindgen(constructor)] - pub fn new() -> Self { - Self { - inner: HashMap::new() - } - } - - pub fn insert(&mut self, key: GroupedQuantityKey, value: Value) { - self.inner.insert(key, value); - } - - pub fn get(&self, key: &GroupedQuantityKey) -> Option { - self.inner.get(key).cloned() - } -} - -// Update the from implementation -impl From<[(GroupedQuantityKey, Value); 1]> for GroupedQuantity { - fn from(arr: [(GroupedQuantityKey, Value); 1]) -> Self { - let mut map = HashMap::new(); - map.insert(arr[0].0, arr[0].1); - Self { inner: map } - } -} - -#[wasm_bindgen] -pub struct Amount { - pub(crate) quantity: Value, - pub(crate) units: Option, -} - -#[wasm_bindgen] -#[derive(Clone)] -pub enum ValueType { - Number, - Range, - Text, - Empty, -} - -#[wasm_bindgen] -#[derive(Clone)] -pub struct Value { - pub value_type: ValueType, - pub number_value: Option, - pub range_start: Option, - pub range_end: Option, - pub text_value: Option, -} - -#[wasm_bindgen] -#[derive(Default)] -pub struct CooklangMetadata { - inner: HashMap, -} - -#[wasm_bindgen] -impl CooklangMetadata { - #[wasm_bindgen(constructor)] - pub fn new() -> Self { - Self { - inner: HashMap::new() - } - } - - pub fn insert(&mut self, key: String, value: String) { - self.inner.insert(key, value); - } - - pub fn get(&self, key: &str) -> Option { - self.inner.get(key).cloned() - } -} - -trait Amountable { - fn extract_amount(&self) -> Amount; -} - -impl Amountable for OriginalQuantity { - fn extract_amount(&self) -> Amount { - let quantity = extract_quantity(&self.value); - - let units = self.unit().as_ref().map(|u| u.to_string()); - - Amount { quantity, units } - } -} - -impl Amountable for OriginalScalableValue { - fn extract_amount(&self) -> Amount { - let quantity = extract_quantity(self); - - Amount { - quantity, - units: None, - } - } -} - -fn extract_quantity(value: &OriginalScalableValue) -> Value { - match value { - OriginalScalableValue::Fixed(value) => extract_value(value), - OriginalScalableValue::Linear(value) => extract_value(value), - OriginalScalableValue::ByServings(values) => extract_value(values.first().unwrap()), - } -} - -fn extract_value(value: &OriginalValue) -> Value { - match value { - OriginalValue::Number(num) => Value { - value_type: ValueType::Number, - number_value: Some(num.value()), - range_start: None, - range_end: None, - text_value: None, - }, - OriginalValue::Range { start, end } => Value { - value_type: ValueType::Range, - number_value: None, - range_start: Some(start.value()), - range_end: Some(end.value()), - text_value: None, - }, - OriginalValue::Text(value) => Value { - value_type: ValueType::Text, - number_value: None, - range_start: None, - range_end: None, - text_value: Some(value.to_string()), - }, - } -} - -// I(dubadub) haven't found a way to export these methods with mutable argument -pub fn add_to_ingredient_list( - list: &mut IngredientList, - name: &String, - quantity_to_add: &GroupedQuantity, -) { - if let Some(quantity) = list.inner.get_mut(name) { - merge_grouped_quantities(quantity, quantity_to_add); - } else { - list.inner.insert(name.to_string(), quantity_to_add.clone()); - } -} - -// O(n2)? find a better way -pub fn merge_ingredient_lists(left: &mut IngredientList, right: &IngredientList) { - right.inner - .iter() - .for_each(|(ingredient_name, grouped_quantity)| { - let quantity = left.inner - .entry(ingredient_name.to_string()) - .or_insert(GroupedQuantity::default()); - - merge_grouped_quantities(quantity, grouped_quantity); - }); -} - -// I(dubadub) haven't found a way to export these methods with mutable argument -// Right should be always smaller? -pub(crate) fn merge_grouped_quantities(left: &mut GroupedQuantity, right: &GroupedQuantity) { - // options here: - // - same units: - // - same value type - // - not the same value type - // - different units - // - no units - // - no amount - // - // \ - // |- => 1.2 litre - // |- => half litre - // |- <,Text> => pinch - // |- <,Empty> => Some - // - // - // TODO define rules on language spec level - - right.iter().for_each(|(key, value)| { - left - .entry(key.clone()) // isn't really necessary? - .and_modify(|v| { - match key.unit_type { - QuantityType::Number => { - let Value::Number { value: assignable } = value else { panic!("Unexpected type") }; - let Value::Number { value: stored } = v else { panic!("Unexpected type") }; - - *stored += assignable - }, - QuantityType::Range => { - let Value::Range { start, end } = value else { panic!("Unexpected type") }; - let Value::Range { start: s, end: e } = v else { panic!("Unexpected type") }; - - // is it even correct? - *s += start; - *e += end; - }, - QuantityType::Text => { - let Value::Text { value: ref assignable } = value else { panic!("Unexpected type") }; - let Value::Text { value: stored } = v else { panic!("Unexpected type") }; - - *stored += assignable; - }, - QuantityType::Empty => {}, // nothing is required to do, Some + Some = Some - - } - }) - .or_insert(value.clone()); - }); -} - -pub(crate) fn into_item(item: &OriginalItem, recipe: &OriginalRecipe) -> Item { - match item { - OriginalItem::Text { value } => Item { - item_type: ItemType::Text, - text: Some(ItemText { - value: value.to_string(), - }), - ingredient: None, - cookware: None, - timer: None, - }, - OriginalItem::Ingredient { index } => { - let ingredient = &recipe.ingredients[*index]; - Item { - item_type: ItemType::Ingredient, - text: None, - ingredient: Some(ItemIngredient { - name: ingredient.name.clone(), - amount: ingredient.quantity.as_ref().map(|q| q.extract_amount()), - }), - cookware: None, - timer: None, - } - } - OriginalItem::Cookware { index } => { - let cookware = &recipe.cookware[*index]; - Item { - item_type: ItemType::Cookware, - text: None, - ingredient: None, - cookware: Some(ItemCookware { - name: cookware.name.clone(), - amount: cookware.quantity.as_ref().map(|q| q.extract_amount()), - }), - timer: None, - } - } - OriginalItem::Timer { index } => { - let timer = &recipe.timers[*index]; - Item { - item_type: ItemType::Timer, - text: None, - ingredient: None, - cookware: None, - timer: Some(ItemTimer { - name: timer.name.clone(), - amount: timer.quantity.as_ref().map(|q| q.extract_amount()), - }), - } - } - OriginalItem::InlineQuantity { index: _ } => Item { - item_type: ItemType::Text, - text: Some(ItemText { - value: "".to_string(), - }), - ingredient: None, - cookware: None, - timer: None, - }, - } -} - -pub(crate) fn into_simple_recipe(recipe: &OriginalRecipe) -> CooklangRecipe { - let mut metadata = CooklangMetadata::new(); - let mut steps: Vec = Vec::new(); - let mut ingredients: IngredientList = IngredientList::new(); - let mut cookware: Vec = Vec::new(); - let mut items: Vec = Vec::new(); - - recipe.sections.iter().for_each(|section| { - section.content.iter().for_each(|content| { - if let cooklang::Content::Step(step) = content { - step.items.iter().for_each(|i| { - let item = into_item(i, recipe); - - match item { - Item { - item_type: ItemType::Ingredient, - ingredient: Some(ref ingredient), - .. - } => { - let quantity = into_group_quantity(&ingredient.amount); - - add_to_ingredient_list(&mut ingredients, &ingredient.name, &quantity); - } - Item { - item_type: ItemType::Cookware, - cookware: Some(ref cookware), - .. - } => { - cookware.push(cookware.clone()); - } - // don't need anything if timer or text - _ => (), - }; - items.push(item); - }); - // TODO: think how to make it faster as we probably - // can switch items content directly into the step object without cloning it - steps.push(Step { - items: items.clone(), - }); - - items.clear(); - } - }); - }); - - recipe.metadata.map.iter().for_each(|(key, value)| { - metadata.insert(key.to_string(), value.to_string()); - }); - - CooklangRecipe { - metadata, - steps, - ingredients, - cookware, - } -} diff --git a/tests/index.test.ts b/tests/index.test.ts index ba9ee14..b501b93 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,10 +1,7 @@ import * as fs from 'fs'; import * as yaml from 'yaml'; -import { Parser } from '../src/index'; -import { State } from '../src/index'; -import { Step } from '../src/cooklang'; +import { parse_recipe } from '../src/index'; -const parser = new Parser(); const testsPath = "./tests"; const testFiles = fs.readdirSync(testsPath).filter((f) => f.endsWith(".yaml")); @@ -17,10 +14,10 @@ testFiles.forEach((testFile) => { >; describe(testFile, () => { - Object.entries(testData).forEach(([name, testEntry]) => { + Object.entries(testData).slice(0, 3).forEach(([name, testEntry]) => { it(name, () => { const { source, result } = testEntry; - const parsed = parser.parse(source); + const parsed = parse_recipe(source); const expected = { steps: result.steps, @@ -28,15 +25,43 @@ testFiles.forEach((testFile) => { }; const actual = { - steps: parsed.steps, + steps: parsed.sections.flatMap((i: any) => i.blocks).flatMap((i: any) => i.step.items).map((i: any) => { + console.log(i); + switch (i.item_type) { + case "text": + return { + type: "text", + value: i.text_value, + } + case "ingredient_ref": + const ingredient = parsed.ingredients[i.ref_index]; + console.log(ingredient); + return { + type: "ingredient", + quantity: ingredient.amount?.quantity, + units: ingredient.amount?.quantity?.units, + name: ingredient.name, + } + case "timer_ref": + const timer = parsed.timers[i.ref_index]; + return { + type: "timer", + name: timer.name, + } + case "cookware_ref": + const cookware = parsed.cookware[i.ref_index]; + return { + type: "cookware", + name: cookware.name, + } + default: + break; + } + }), metadata: parsed.metadata, }; - const state = new State(); - const { value, error } = state.parse_full(source, false); - - - expect(value).toStrictEqual(result); + expect(expected).toStrictEqual(actual); }); }); });