parse magic draw project files
This commit is contained in:
commit
ef87fa39c3
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
dist
|
986
Cargo.lock
generated
Normal file
986
Cargo.lock
generated
Normal file
@ -0,0 +1,986 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||
|
||||
[[package]]
|
||||
name = "anymap2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "boolinator"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20"
|
||||
dependencies = [
|
||||
"gloo-console",
|
||||
"gloo-dialogs",
|
||||
"gloo-events",
|
||||
"gloo-file",
|
||||
"gloo-history",
|
||||
"gloo-net",
|
||||
"gloo-render",
|
||||
"gloo-storage",
|
||||
"gloo-timers",
|
||||
"gloo-utils",
|
||||
"gloo-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-console"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-dialogs"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-events"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-file"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
|
||||
dependencies = [
|
||||
"gloo-events",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-history"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7"
|
||||
dependencies = [
|
||||
"gloo-events",
|
||||
"gloo-utils",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_urlencoded",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-net"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-render"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-storage"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-utils"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-worker"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a"
|
||||
dependencies = [
|
||||
"anymap2",
|
||||
"bincode",
|
||||
"gloo-console",
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "implicit-clone"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a505da2f89befd87ab425d252795f0f285e100b43e7d22d29528df3d9a576793"
|
||||
dependencies = [
|
||||
"lazy-regex-proc_macros",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex-proc_macros"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8edfc11b8f56ce85e207e62ea21557cfa09bb24a8f6b04ae181b086ff8611c22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "magic-sql-gen"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy-regex",
|
||||
"thiserror",
|
||||
"xml-rs",
|
||||
"yew",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pinned"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"rustversion",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prokio"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"gloo",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project",
|
||||
"pinned",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"pin-project-lite",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
|
||||
[[package]]
|
||||
name = "yew"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
"gloo",
|
||||
"implicit-clone",
|
||||
"indexmap",
|
||||
"js-sys",
|
||||
"prokio",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"yew-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yew-macro"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301"
|
||||
dependencies = [
|
||||
"boolinator",
|
||||
"once_cell",
|
||||
"prettyplease",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
]
|
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "magic-sql-gen"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
xml-rs = "0.8.4"
|
||||
yew = { version="0.20", features=["csr"] }
|
||||
anyhow = "1.0.69"
|
||||
thiserror = "1.0.38"
|
||||
lazy-regex = "2.4.1"
|
||||
|
||||
[dependencies.zip]
|
||||
version = "0.6.4"
|
||||
default-features = false
|
||||
features=["deflate"]
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
Copyright © 2023 Rokas Puzonas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
8
index.html
Normal file
8
index.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Trunk Template</title>
|
||||
<link data-trunk rel="sass" href="index.scss" />
|
||||
</head>
|
||||
</html>
|
35
index.scss
Normal file
35
index.scss
Normal file
@ -0,0 +1,35 @@
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
background: linear-gradient(to bottom right, #444444, #009a5b);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
main {
|
||||
color: #fff6d5;
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 20em;
|
||||
}
|
||||
|
||||
.heart:after {
|
||||
content: "❤️";
|
||||
|
||||
font-size: 1.75em;
|
||||
}
|
||||
|
||||
h1 + .subtitle {
|
||||
display: block;
|
||||
margin-top: -1em;
|
||||
}
|
141
src/magicdraw_parser/ddl_parser.rs
Normal file
141
src/magicdraw_parser/ddl_parser.rs
Normal file
@ -0,0 +1,141 @@
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
use xml::attribute::OwnedAttribute;
|
||||
use xml::name::OwnedName;
|
||||
use xml::{EventReader, reader::XmlEvent};
|
||||
use zip::ZipArchive;
|
||||
use anyhow::{Result, Context, Ok};
|
||||
|
||||
use crate::magicdraw_parser::utils::get_attribute;
|
||||
|
||||
use super::utils::{check_name, check_attribute, MyEventReader, parse_element};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DDLClass {
|
||||
pub class_id: String,
|
||||
pub property_ids: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DDLScript {
|
||||
pub script_id: String,
|
||||
pub classess: Vec<DDLClass>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DDLProject {
|
||||
pub model_id: String,
|
||||
pub scripts: Vec<DDLScript>
|
||||
}
|
||||
|
||||
fn get_id_from_href(attrs: &[OwnedAttribute]) -> Option<String> {
|
||||
let href = get_attribute(attrs, None, "href").ok()?;
|
||||
let parts = href.split_once("#")?;
|
||||
Some(parts.1.to_string())
|
||||
}
|
||||
|
||||
fn parse_class<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<DDLClass> {
|
||||
let mut property_ids = vec![];
|
||||
let mut class_id = None;
|
||||
|
||||
fn is_model_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "modelElement") && check_attribute(&attributes, Some("xsi"), "type", "uml:Class")
|
||||
}
|
||||
|
||||
fn is_property_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "modelElement") && check_attribute(&attributes, Some("xsi"), "type", "uml:Property")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_model_element(&name, &attrs) && class_id.is_none() {
|
||||
class_id = get_id_from_href(&attrs);
|
||||
} else if is_property_element(&name, &attrs) {
|
||||
property_ids.push(get_id_from_href(&attrs).context("Property id not found")?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(DDLClass {
|
||||
class_id: class_id.context("Missing class id")?,
|
||||
property_ids
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_script<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<DDLScript> {
|
||||
let mut classess = vec![];
|
||||
let mut script_id = None;
|
||||
|
||||
fn is_model_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "modelElement") && check_attribute(&attributes, Some("xsi"), "type", "uml:Component")
|
||||
}
|
||||
|
||||
fn is_class_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "objects") && check_attribute(&attributes, Some("xsi"), "type", "md.ce.rt.objects:RTClassObject")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_model_element(&name, &attrs) && script_id.is_none() {
|
||||
script_id = get_id_from_href(&attrs);
|
||||
} else if is_class_element(&name, &attrs) {
|
||||
classess.push(parse_class(p, &attrs)?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(DDLScript {
|
||||
script_id: script_id.context("Missing script id")?,
|
||||
classess
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_project<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<DDLProject> {
|
||||
let mut scripts = vec![];
|
||||
let mut model_id = None;
|
||||
|
||||
fn is_model_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "modelElement") && check_attribute(&attributes, Some("xsi"), "type", "uml:Model")
|
||||
}
|
||||
|
||||
fn is_component_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "objects") && check_attribute(&attributes, Some("xsi"), "type", "md.ce.rt.objects:RTComponent")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_model_element(&name, &attrs) && model_id.is_none() {
|
||||
model_id = get_id_from_href(&attrs);
|
||||
} else if is_component_element(&name, &attrs) {
|
||||
scripts.push(parse_script(p, &attrs)?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(DDLProject {
|
||||
model_id: model_id.context("Missing model id")?,
|
||||
scripts
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_ddl_scripts<R: Read + Seek>(project: &mut ZipArchive<R>) -> Result<Vec<DDLProject>> {
|
||||
let mut ddl_scripts = vec![];
|
||||
|
||||
let file = project.by_name("personal-com.nomagic.magicdraw.ce.dmn.personaldmncodeengineering")?;
|
||||
let mut parser: MyEventReader<_> = EventReader::new(file).into();
|
||||
|
||||
fn is_project_element(name: &OwnedName, attributes: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "contents") && check_attribute(&attributes, Some("xsi"), "type", "md.ce.ddl.rt.objects:DDLProjectObject")
|
||||
}
|
||||
|
||||
loop {
|
||||
match parser.next()? {
|
||||
XmlEvent::StartElement { name, attributes, .. } => {
|
||||
if is_project_element(&name, &attributes) {
|
||||
ddl_scripts.push(parse_project(&mut parser, &attributes)?);
|
||||
}
|
||||
},
|
||||
XmlEvent::EndDocument => { break; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ddl_scripts)
|
||||
}
|
263
src/magicdraw_parser/mod.rs
Normal file
263
src/magicdraw_parser/mod.rs
Normal file
@ -0,0 +1,263 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
mod utils;
|
||||
mod uml_model_parser;
|
||||
mod ddl_parser;
|
||||
mod sql_types_parser;
|
||||
|
||||
use std::{io::{Read, Seek}, collections::HashSet};
|
||||
use anyhow::{Result, Context};
|
||||
use lazy_regex::regex_captures;
|
||||
use zip::ZipArchive;
|
||||
|
||||
use crate::unwrap_opt_continue;
|
||||
|
||||
use self::{uml_model_parser::{parse_uml_model, UMLModel, UMLClass, UMLModifier, UMLNullableModifier, UMLPrimaryKeyModifier, UMLTypeModifier, UMLForeignKeyModifier}, ddl_parser::parse_ddl_scripts, sql_types_parser::{parse_sql_types, SQLTypeName}};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SQLType {
|
||||
Int,
|
||||
Decimal,
|
||||
Date,
|
||||
Float,
|
||||
Bool,
|
||||
Char(u8),
|
||||
Varchar(u16),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SQLCheckConstraint {
|
||||
OneOf(Vec<String>),
|
||||
Freeform(String)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SQLColumn {
|
||||
name: String,
|
||||
sql_type: SQLType,
|
||||
primary_key: bool,
|
||||
nullable: bool,
|
||||
foreign_key: Option<(String, String)>,
|
||||
check_constraint: Option<SQLCheckConstraint>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SQLTable {
|
||||
name: String,
|
||||
columns: Vec<SQLColumn>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SQLTableCollection {
|
||||
tables: Vec<SQLTable>
|
||||
}
|
||||
|
||||
fn find_class_by_id<'a>(models: &'a [UMLModel], id: &str) -> Option<&'a UMLClass> {
|
||||
for model in models {
|
||||
for package in &model.packages {
|
||||
if let Some(class) = package.classess.iter().find(|t| t.id.eq(id)) {
|
||||
return Some(class);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn is_nullabe(modifiers: &[UMLModifier], property: &str) -> bool {
|
||||
for modifier in modifiers {
|
||||
if let UMLModifier::Nullable(UMLNullableModifier { property_id, nullable }) = modifier {
|
||||
if property_id.eq(property) {
|
||||
return *nullable;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_primary_key(modifiers: &[UMLModifier], property: &str) -> bool {
|
||||
for modifier in modifiers {
|
||||
if let UMLModifier::PirmaryKey(UMLPrimaryKeyModifier { property_id }) = modifier {
|
||||
if property_id.eq(property) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn get_type_modifier<'a>(modifiers: &'a [UMLModifier], property: &str) -> Option<&'a str> {
|
||||
for modifier in modifiers {
|
||||
if let UMLModifier::Type(UMLTypeModifier { property_id, modifier }) = modifier {
|
||||
if property_id.eq(property) {
|
||||
return Some(modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_foreign_key_constraint<'a>(modifiers: &'a [UMLModifier], from_id: &str) -> Option<&'a str> {
|
||||
for modifier in modifiers {
|
||||
if let UMLModifier::ForeignKey(UMLForeignKeyModifier { from_property_id, to_property_id }) = modifier {
|
||||
if from_property_id.eq(from_id) {
|
||||
return Some(&to_property_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_foreign_key(modifiers: &[UMLModifier], classess: &[&UMLClass], property: &str) -> Result<Option<(String, String)>> {
|
||||
let to_id = get_foreign_key_constraint(modifiers, property);
|
||||
if to_id.is_none() {
|
||||
return Ok(None)
|
||||
}
|
||||
let to_id = to_id.unwrap();
|
||||
|
||||
for class in classess {
|
||||
for property in &class.properties {
|
||||
if property.id.eq(to_id) {
|
||||
let property_name = property.name.clone().context("Missing property name")?;
|
||||
let class_name = class.name.clone().context("Missing class name")?;
|
||||
return Ok(Some((class_name, property_name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn parse_check_constraint(str: &str) -> SQLCheckConstraint {
|
||||
fn try_parse_one_of(str: &str) -> Option<SQLCheckConstraint> {
|
||||
let (_, inner) = regex_captures!(r#"^in \((.+)\)$"#, str)?;
|
||||
let mut variants = vec![];
|
||||
for part in inner.split(", ") {
|
||||
let (_, variant) = regex_captures!(r#"^'(.+)'$"#, part)?;
|
||||
variants.push(variant.to_string());
|
||||
}
|
||||
|
||||
Some(SQLCheckConstraint::OneOf(variants))
|
||||
}
|
||||
|
||||
try_parse_one_of(str)
|
||||
.unwrap_or(SQLCheckConstraint::Freeform(str.to_string()))
|
||||
}
|
||||
|
||||
// TODO: Refactor this function, less nesting would be good
|
||||
fn get_sql_check_constraint<'a>(models: &'a [UMLModel], property_name: &str) -> Option<SQLCheckConstraint> {
|
||||
for model in models {
|
||||
for package in &model.packages {
|
||||
for class in &package.classess {
|
||||
for constraint in &class.constraints {
|
||||
let prop_name = unwrap_opt_continue!(&constraint.property_name);
|
||||
let body = unwrap_opt_continue!(&constraint.body);
|
||||
|
||||
if prop_name.eq(property_name) && constraint.body.is_some() {
|
||||
return Some(parse_check_constraint(body));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_sql_type(modifiers: &[UMLModifier], type_name: SQLTypeName, property: &str) -> Result<SQLType> {
|
||||
Ok(match type_name {
|
||||
SQLTypeName::Int => SQLType::Int,
|
||||
SQLTypeName::Date => SQLType::Date,
|
||||
SQLTypeName::Float => SQLType::Float,
|
||||
SQLTypeName::Bool => SQLType::Bool,
|
||||
SQLTypeName::Decimal => SQLType::Decimal,
|
||||
SQLTypeName::Char => {
|
||||
if let Some(type_modifier) = get_type_modifier(modifiers, property) {
|
||||
let (_, size) = regex_captures!(r#"^\((\d+)\)$"#, type_modifier)
|
||||
.context("Type modifier doesn't match format")?;
|
||||
SQLType::Char(size.parse()?)
|
||||
} else {
|
||||
// TODO: Add better error message to say which table is missing type modifier
|
||||
// For now just pick a defautl arbitrarily
|
||||
SQLType::Char(31)
|
||||
}
|
||||
},
|
||||
SQLTypeName::Varchar => {
|
||||
if let Some(type_modifier) = get_type_modifier(modifiers, property) {
|
||||
let (_, size) = regex_captures!(r#"^\((\d+)\)$"#, type_modifier)
|
||||
.context("Type modifier doesn't match format")?;
|
||||
SQLType::Varchar(size.parse()?)
|
||||
} else {
|
||||
// TODO: Add better error message to say which table is missing type modifier
|
||||
// For now just pick a defautl arbitrarily
|
||||
SQLType::Varchar(255)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn get_used_types<'a>(models: &'a [UMLModel]) -> HashSet<&'a String> {
|
||||
models.iter()
|
||||
.flat_map(|model| &model.packages)
|
||||
.flat_map(|package| &package.classess)
|
||||
.flat_map(|class| &class.properties)
|
||||
.filter_map(|property| property.type_href.as_ref())
|
||||
.collect::<HashSet<_>>()
|
||||
}
|
||||
|
||||
pub fn parse_project<R: Read + Seek>(project_file: R) -> Result<Vec<SQLTableCollection>> {
|
||||
let mut zip = ZipArchive::new(project_file).unwrap();
|
||||
|
||||
let (models, modifiers) = parse_uml_model(&mut zip)?;
|
||||
let ddl_scripts = parse_ddl_scripts(&mut zip)?;
|
||||
let sql_type_names = parse_sql_types(&mut zip, &get_used_types(&models))?;
|
||||
|
||||
let mut collections = vec![];
|
||||
for ddl_project in ddl_scripts {
|
||||
for ddl_script in ddl_project.scripts {
|
||||
let mut tables = vec![];
|
||||
|
||||
let model_properties = ddl_script.classess.iter()
|
||||
.flat_map(|class| class.property_ids.iter().map(|prop| (&class.class_id, prop)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut model_classess = vec![];
|
||||
for ddl_class in &ddl_script.classess {
|
||||
let model_class = find_class_by_id(&models, &ddl_class.class_id).context("UML class not found")?;
|
||||
model_classess.push(model_class);
|
||||
}
|
||||
|
||||
for (ddl_class, model_class) in ddl_script.classess.iter().zip(&model_classess) {
|
||||
let name = model_class.name.clone().context("UML class name not found")?;
|
||||
|
||||
let mut columns = vec![];
|
||||
for property_id in &ddl_class.property_ids {
|
||||
let property = model_class.properties.iter().find(|p| p.id.eq(property_id)).context("Property not found")?;
|
||||
let prop_name = unwrap_opt_continue!(&property.name).clone();
|
||||
|
||||
let type_href = unwrap_opt_continue!(&property.type_href);
|
||||
let type_name = sql_type_names.get(type_href).context("Proerty type name conversion not found")?;
|
||||
|
||||
let check_constraint = get_sql_check_constraint(&models, &prop_name);
|
||||
let foreign_key = get_foreign_key(&modifiers, &model_classess, property_id)?;
|
||||
|
||||
columns.push(SQLColumn {
|
||||
name: prop_name,
|
||||
sql_type: get_sql_type(&modifiers, *type_name, property_id)?,
|
||||
primary_key: is_primary_key(&modifiers, property_id),
|
||||
nullable: is_nullabe(&modifiers, property_id),
|
||||
foreign_key,
|
||||
check_constraint,
|
||||
})
|
||||
}
|
||||
|
||||
tables.push(SQLTable {
|
||||
name,
|
||||
columns
|
||||
})
|
||||
}
|
||||
collections.push(SQLTableCollection { tables })
|
||||
}
|
||||
}
|
||||
|
||||
Ok(collections)
|
||||
}
|
169
src/magicdraw_parser/sql_types_parser.rs
Normal file
169
src/magicdraw_parser/sql_types_parser.rs
Normal file
@ -0,0 +1,169 @@
|
||||
use std::{io::{Read, Seek}, collections::{HashMap, HashSet}};
|
||||
|
||||
use xml::{EventReader, reader::XmlEvent, attribute::OwnedAttribute, name::OwnedName};
|
||||
use zip::ZipArchive;
|
||||
use anyhow::{Result, Context, bail};
|
||||
|
||||
use crate::unwrap_opt_continue;
|
||||
|
||||
use super::utils::{MyEventReader, check_name, parse_element, get_attribute, check_attribute};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct UsedPackage {
|
||||
share_point_id: String,
|
||||
name: String,
|
||||
needed_types: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum SQLTypeName {
|
||||
Int,
|
||||
Decimal,
|
||||
Date,
|
||||
Float,
|
||||
Bool,
|
||||
Char,
|
||||
Varchar
|
||||
}
|
||||
|
||||
fn get_used_project_name(attrs: &[OwnedAttribute]) -> Option<&str> {
|
||||
let project_uri = get_attribute(&attrs, None, "usedProjectURI").ok()?;
|
||||
project_uri.split("/").last()
|
||||
}
|
||||
|
||||
fn parse_used_package<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute], needed_types: &[&str]) -> Result<UsedPackage> {
|
||||
let mut share_point_id = None;
|
||||
let project_uri = get_attribute(&attrs, None, "usedProjectURI")?;
|
||||
let name = project_uri.split("/").last().unwrap();
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if share_point_id.is_none() && check_name(&name, None, "mountPoints") {
|
||||
share_point_id = get_attribute(&attrs, None, "sharePointID").ok().map(str::to_string);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(UsedPackage {
|
||||
name: name.to_string(),
|
||||
share_point_id: share_point_id.context("Share point id not found")?,
|
||||
needed_types: needed_types.iter().map(|s| s.to_string()).collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn list_used_packages<R: Read>(file: R, needed_types: &HashSet<&String>) -> Result<Vec<UsedPackage>> {
|
||||
let mut packages = vec![];
|
||||
|
||||
let mut needed_types_per_package = HashMap::new();
|
||||
for needed_type in needed_types.iter() {
|
||||
let (package_name, type_id) = unwrap_opt_continue!(needed_type.split_once("#"));
|
||||
let ids = needed_types_per_package.entry(package_name).or_insert(vec![]);
|
||||
ids.push(type_id);
|
||||
}
|
||||
|
||||
let mut parser: MyEventReader<_> = EventReader::new(file).into();
|
||||
loop {
|
||||
match parser.next()? {
|
||||
XmlEvent::StartElement { name, attributes, .. } => {
|
||||
if check_name(&name, None, "projectUsages") {
|
||||
let project_name = unwrap_opt_continue!(get_used_project_name(&attributes));
|
||||
if let Some(needed_types_for_package) = needed_types_per_package.get(&project_name) {
|
||||
packages.push(parse_used_package(&mut parser, &attributes, needed_types_for_package)?);
|
||||
}
|
||||
}
|
||||
},
|
||||
XmlEvent::EndDocument => { break; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(packages)
|
||||
}
|
||||
|
||||
fn is_umodel_snapshot_file(filename: &str) -> bool {
|
||||
filename.ends_with("_resource_com$dnomagic$dmagicdraw$duml_umodel$dshared_umodel$dsnapshot")
|
||||
}
|
||||
|
||||
fn parse_type_name(str: &str) -> Result<SQLTypeName> {
|
||||
use SQLTypeName::*;
|
||||
Ok(match str {
|
||||
"decimal" => Decimal,
|
||||
"char" => Char,
|
||||
"varchar" => Varchar,
|
||||
"float" => Float,
|
||||
"Integer" | "integer" | "int" => Int,
|
||||
"date" => Date,
|
||||
"Boolean" => Bool,
|
||||
_ => bail!("Unknown SQL type: '{}'", str)
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_types_package<R: Read>(parser: &mut MyEventReader<R>) -> Result<Vec<(String, SQLTypeName)>> {
|
||||
let mut types = vec![];
|
||||
|
||||
fn is_primitive_type_element(name: &OwnedName, attrs: &[OwnedAttribute]) -> bool {
|
||||
check_name(&name, None, "packagedElement") && check_attribute(&attrs, Some("xsi"), "type", "uml:PrimitiveType")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_primitive_type_element(&name, &attrs) {
|
||||
let type_name = get_attribute(&attrs, None, "name")?;
|
||||
if !type_name.eq("StructuredExpression") {
|
||||
types.push((
|
||||
get_attribute(&attrs, Some("xmi"), "id")?.to_string(),
|
||||
parse_type_name(type_name)?
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(types)
|
||||
}
|
||||
|
||||
fn parse_primitive_types<R: Read>(reader: R, used_packages: &[UsedPackage]) -> Result<Vec<(String, SQLTypeName)>> {
|
||||
let mut types = vec![];
|
||||
|
||||
let mut parser: MyEventReader<_> = EventReader::new(reader).into();
|
||||
loop {
|
||||
match parser.next()? {
|
||||
XmlEvent::StartElement { name, attributes, .. } => {
|
||||
if check_name(&name, Some("uml"), "Package") {
|
||||
if let Some(id) = get_attribute(&attributes, None, "ID").ok() {
|
||||
if let Some(package) = used_packages.iter().find(|p| p.share_point_id.eq(id)) {
|
||||
let package_types = parse_types_package(&mut parser)?
|
||||
.into_iter()
|
||||
.filter(|t| package.needed_types.contains(&t.0))
|
||||
.map(|(id, type_name)| (format!("{}#{}", package.name, id), type_name));
|
||||
types.extend(package_types);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
XmlEvent::EndDocument => { break; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(types)
|
||||
}
|
||||
|
||||
pub fn parse_sql_types<R: Read + Seek>(project: &mut ZipArchive<R>, needed_types: &HashSet<&String>) -> Result<HashMap<String, SQLTypeName>> {
|
||||
let mut type_names = HashMap::new();
|
||||
|
||||
let meta_model_file = project.by_name("com.nomagic.ci.metamodel.project")?;
|
||||
let used_packages = list_used_packages(meta_model_file, needed_types)?;
|
||||
|
||||
let snapshot_files = project.file_names()
|
||||
.filter(|f| is_umodel_snapshot_file(f))
|
||||
.map(|f| f.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for filename in &snapshot_files {
|
||||
let f = project.by_name(filename).unwrap();
|
||||
for (id, type_name) in parse_primitive_types(f, &used_packages)? {
|
||||
type_names.insert(id, type_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(type_names)
|
||||
}
|
294
src/magicdraw_parser/uml_model_parser.rs
Normal file
294
src/magicdraw_parser/uml_model_parser.rs
Normal file
@ -0,0 +1,294 @@
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
use xml::{EventReader, reader::XmlEvent, attribute::OwnedAttribute, name::OwnedName};
|
||||
use zip::ZipArchive;
|
||||
use anyhow::{Result, Context};
|
||||
|
||||
use crate::{unwrap_err_continue, unwrap_opt_continue};
|
||||
|
||||
use super::utils::{check_name, parse_element, get_attribute, check_attribute, MyEventReader, ParseProjectError, get_element_characters};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLProperty {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub is_id: bool,
|
||||
pub type_href: Option<String>
|
||||
}
|
||||
|
||||
// TODO: Make this an enum? Because from what I have seen there were only 2 cases,
|
||||
// * Constraint applied to property
|
||||
// * Constraint applied to class
|
||||
#[derive(Debug)]
|
||||
pub struct UMLConstraint {
|
||||
pub id: String,
|
||||
pub class_id: Option<String>,
|
||||
pub property_id: Option<String>,
|
||||
pub property_name: Option<String>,
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLClass {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub properties: Vec<UMLProperty>,
|
||||
pub constraints: Vec<UMLConstraint>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLPackage {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub classess: Vec<UMLClass>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLModel {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub packages: Vec<UMLPackage>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLPrimaryKeyModifier {
|
||||
pub property_id: String
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLNullableModifier {
|
||||
pub property_id: String,
|
||||
pub nullable: bool
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLForeignKeyModifier {
|
||||
pub from_property_id: String,
|
||||
pub to_property_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLUniqueModifier {
|
||||
pub property_id: String
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UMLTypeModifier {
|
||||
pub property_id: String,
|
||||
pub modifier: String
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UMLModifier {
|
||||
Unique(UMLUniqueModifier),
|
||||
PirmaryKey(UMLPrimaryKeyModifier),
|
||||
Nullable(UMLNullableModifier),
|
||||
ForeignKey(UMLForeignKeyModifier),
|
||||
Type(UMLTypeModifier)
|
||||
}
|
||||
|
||||
fn parse_property<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<UMLProperty> {
|
||||
let id = get_attribute(attrs, Some("xmi"), "id")?.into();
|
||||
let name = get_attribute(attrs, None, "name").ok().map(str::to_string);
|
||||
let is_id = get_attribute(attrs, None, "isID").unwrap_or("false").eq("true");
|
||||
let mut type_href = None;
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if check_name(&name, None, "type") && type_href.is_none() {
|
||||
if let Ok(value) = get_attribute(&attrs, None, "href") {
|
||||
type_href = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(UMLProperty {
|
||||
id,
|
||||
name,
|
||||
is_id,
|
||||
type_href
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_constraint<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<Option<UMLConstraint>> {
|
||||
let id = get_attribute(attrs, Some("xmi"), "id")?.into();
|
||||
let mut constrainted_element_id = None;
|
||||
let mut language = None;
|
||||
let mut body = None;
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if check_name(&name, None, "constrainedElement") && constrainted_element_id.is_none() {
|
||||
constrainted_element_id = get_attribute(&attrs, Some("xmi"), "idref").ok().map(str::to_string);
|
||||
} else if check_name(&name, None, "body") && body.is_none() {
|
||||
let contents = get_element_characters(p)?;
|
||||
if contents.len() > 0 {
|
||||
body = Some(contents);
|
||||
}
|
||||
} else if check_name(&name, None, "language") && language.is_none() {
|
||||
language = Some(get_element_characters(p)?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if language.eq(&Some("SQL".into())) && body.is_some() {
|
||||
if let Some((prop_name, check_body)) = body.unwrap().split_once(" in ") {
|
||||
return Ok(Some(UMLConstraint {
|
||||
id,
|
||||
class_id: Some(constrainted_element_id.context("Missing class id")?),
|
||||
body: Some(format!("in {}", check_body)),
|
||||
property_id: None,
|
||||
property_name: Some(prop_name.into())
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(Some(UMLConstraint {
|
||||
id,
|
||||
property_id: Some(constrainted_element_id.context("Missing property id")?),
|
||||
body: None,
|
||||
class_id: None,
|
||||
property_name: None
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_class<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<UMLClass> {
|
||||
let mut properties = vec![];
|
||||
let mut consraints = vec![];
|
||||
let id = get_attribute(attrs, Some("xmi"), "id")?.into();
|
||||
let name = get_attribute(attrs, None, "name").ok().map(str::to_string);
|
||||
|
||||
fn is_property_element(name: &OwnedName, attrs: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "ownedAttribute") && check_attribute(&attrs, Some("xmi"), "type", "uml:Property")
|
||||
}
|
||||
|
||||
fn is_constraint_element(name: &OwnedName, attrs: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "ownedRule") && check_attribute(&attrs, Some("xmi"), "type", "uml:Constraint")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_property_element(&name, &attrs) {
|
||||
properties.push(parse_property(p, &attrs)?);
|
||||
} else if is_constraint_element(&name, &attrs) {
|
||||
if let Some(constraint) = parse_constraint(p, &attrs)? {
|
||||
consraints.push(constraint);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(UMLClass {
|
||||
id,
|
||||
name,
|
||||
properties,
|
||||
constraints: consraints,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_package<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<UMLPackage> {
|
||||
let mut classess = vec![];
|
||||
let id = get_attribute(attrs, Some("xmi"), "id")?.into();
|
||||
let name = get_attribute(attrs, None, "name").ok().map(str::to_string);
|
||||
|
||||
fn is_class_element(name: &OwnedName, attrs: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "packagedElement") && check_attribute(&attrs, Some("xmi"), "type", "uml:Class")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_class_element(&name, &attrs) {
|
||||
classess.push(parse_class(p, &attrs)?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(UMLPackage {
|
||||
id,
|
||||
name,
|
||||
classess
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_model<R: Read>(parser: &mut MyEventReader<R>, attrs: &[OwnedAttribute]) -> Result<UMLModel> {
|
||||
let mut packages = vec![];
|
||||
let id = get_attribute(attrs, Some("xmi"), "id")?.into();
|
||||
let name = get_attribute(attrs, None, "name")?.into();
|
||||
|
||||
fn is_package_element(name: &OwnedName, attrs: &[OwnedAttribute]) -> bool {
|
||||
check_name(name, None, "packagedElement") && check_attribute(&attrs, Some("xmi"), "type", "uml:Package")
|
||||
}
|
||||
|
||||
parse_element(parser, &mut |p, name, attrs| {
|
||||
if is_package_element(&name, &attrs) {
|
||||
packages.push(parse_package(p, &attrs)?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(UMLModel {
|
||||
id,
|
||||
name,
|
||||
packages
|
||||
})
|
||||
}
|
||||
|
||||
fn find_constraint_by_id<'a>(models: &'a [UMLModel], id: &str) -> Option<&'a UMLConstraint> {
|
||||
for model in models {
|
||||
for package in &model.packages {
|
||||
for class in &package.classess {
|
||||
for constraint in &class.constraints {
|
||||
if constraint.id.eq(id) {
|
||||
return Some(constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn parse_uml_model<R: Read + Seek>(project: &mut ZipArchive<R>) -> Result<(Vec<UMLModel>, Vec<UMLModifier>)> {
|
||||
let mut models = vec![];
|
||||
let mut modifiers = vec![];
|
||||
|
||||
let file = project.by_name("com.nomagic.magicdraw.uml_model.model")?;
|
||||
let mut parser: MyEventReader<_> = EventReader::new(file).into();
|
||||
|
||||
loop {
|
||||
match parser.next()? {
|
||||
XmlEvent::StartElement { name, attributes, .. } => {
|
||||
if check_name(&name, Some("uml"), "Model") {
|
||||
models.push(parse_model(&mut parser, &attributes)?);
|
||||
|
||||
} else if check_name(&name, Some("SQLProfile"), "PrimaryKey") {
|
||||
let constraint_id = unwrap_err_continue!(get_attribute(&attributes, None, "base_Constraint"));
|
||||
let constraint = unwrap_opt_continue!(find_constraint_by_id(&models, constraint_id));
|
||||
let property_id = unwrap_opt_continue!(&constraint.property_id).clone();
|
||||
modifiers.push(UMLModifier::PirmaryKey(UMLPrimaryKeyModifier { property_id }));
|
||||
|
||||
} else if check_name(&name, Some("SQLProfile"), "PKMember") {
|
||||
let property_id = unwrap_err_continue!(get_attribute(&attributes, None, "base_Property")).to_string();
|
||||
modifiers.push(UMLModifier::PirmaryKey(UMLPrimaryKeyModifier { property_id }));
|
||||
|
||||
} else if check_name(&name, Some("SQLProfile"), "Column") {
|
||||
let property_id = unwrap_err_continue!(get_attribute(&attributes, None, "base_Property")).to_string();
|
||||
let nullable = unwrap_err_continue!(get_attribute(&attributes, None, "nullable")).eq("true");
|
||||
modifiers.push(UMLModifier::Nullable(UMLNullableModifier { property_id, nullable }));
|
||||
|
||||
} else if check_name(&name, Some("MagicDraw_Profile"), "typeModifier") {
|
||||
let property_id = unwrap_err_continue!(get_attribute(&attributes, None, "base_Element")).into();
|
||||
let modifier = unwrap_err_continue!(get_attribute(&attributes, None, "typeModifier")).into();
|
||||
modifiers.push(UMLModifier::Type(UMLTypeModifier { property_id, modifier }));
|
||||
|
||||
} else if check_name(&name, Some("SQLProfile"), "FK") {
|
||||
let from_property_id = unwrap_err_continue!(get_attribute(&attributes, None, "members")).into();
|
||||
let to_property_id = unwrap_err_continue!(get_attribute(&attributes, None, "referencedMembers")).into();
|
||||
modifiers.push(UMLModifier::ForeignKey(UMLForeignKeyModifier { from_property_id, to_property_id }));
|
||||
}
|
||||
},
|
||||
XmlEvent::EndDocument => { break; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((models, modifiers))
|
||||
}
|
140
src/magicdraw_parser/utils.rs
Normal file
140
src/magicdraw_parser/utils.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use std::io::Read;
|
||||
|
||||
use xml::{EventReader, reader::XmlEvent, name::OwnedName, attribute::OwnedAttribute};
|
||||
use anyhow::Result;
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct MyEventReader<R: Read> {
|
||||
depth: u32,
|
||||
event_reader: EventReader<R>
|
||||
}
|
||||
|
||||
impl<R: Read> MyEventReader<R> {
|
||||
pub fn next(&mut self) -> Result<XmlEvent> {
|
||||
let event = self.event_reader.next()?;
|
||||
if let XmlEvent::StartElement { .. } = event {
|
||||
self.depth += 1;
|
||||
} else if let XmlEvent::EndElement { .. } = event {
|
||||
self.depth -= 1;
|
||||
}
|
||||
Ok(event)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn depth(&self) -> u32 {
|
||||
self.depth
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> From<EventReader<R>> for MyEventReader<R> {
|
||||
fn from(event_reader: EventReader<R>) -> Self {
|
||||
MyEventReader {
|
||||
depth: 0,
|
||||
event_reader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum ParseProjectError {
|
||||
#[error("XML attribute '{}' not found", format_name_from_parts(.0, .1))]
|
||||
AttributeNotFound(Option<String>, String),
|
||||
|
||||
#[error("Unexpected end of XML document")]
|
||||
EndOfDocument
|
||||
}
|
||||
|
||||
fn format_name_from_parts(prefix: &Option<String>, local_name: &str) -> String {
|
||||
if let Some(prefix) = &prefix {
|
||||
format!("{}:{}", prefix, local_name)
|
||||
} else {
|
||||
local_name.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_name(name: &OwnedName) -> String {
|
||||
format_name_from_parts(&name.prefix, &name.local_name)
|
||||
}
|
||||
|
||||
pub fn check_name(name: &OwnedName, prefix: Option<&str>, local_name: &str) -> bool {
|
||||
name.local_name.eq(local_name) && name.prefix_ref().eq(&prefix)
|
||||
}
|
||||
|
||||
pub fn get_attribute<'a>(attributes: &'a [OwnedAttribute], prefix: Option<&str>, name: &str) -> Result<&'a str, ParseProjectError> {
|
||||
Ok(attributes.iter()
|
||||
.find(|attr| check_name(&attr.name, prefix, name))
|
||||
.map(|attr| &attr.value[..])
|
||||
.ok_or_else(
|
||||
|| ParseProjectError::AttributeNotFound(prefix.map(|s| s.to_owned()), name.to_owned()),
|
||||
)?)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn check_attribute(attributes: &[OwnedAttribute], prefix: Option<&str>, name: &str, expected_value: &str) -> bool {
|
||||
if let Ok(attr) = get_attribute(attributes, prefix, name) {
|
||||
return attr.eq(expected_value);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn get_element_characters<R: Read>(parser: &mut MyEventReader<R>) -> Result<String> {
|
||||
let mut parts = vec![];
|
||||
|
||||
loop {
|
||||
match parser.next()? {
|
||||
XmlEvent::Characters(text) => {
|
||||
parts.push(text);
|
||||
},
|
||||
XmlEvent::EndElement { name } => {
|
||||
break;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(parts.join(" "))
|
||||
}
|
||||
|
||||
pub fn parse_element<R: Read, F>(parser: &mut MyEventReader<R>, process_element: &mut F) -> Result<()>
|
||||
where F: FnMut(&mut MyEventReader<R>, OwnedName, Vec<OwnedAttribute>) -> Result<()>
|
||||
{
|
||||
|
||||
let starting_depth = parser.depth();
|
||||
loop {
|
||||
match parser.next()? {
|
||||
XmlEvent::StartElement { name, attributes, .. } => {
|
||||
process_element(parser, name, attributes)?;
|
||||
if parser.depth() == starting_depth-1 { break; }
|
||||
}
|
||||
XmlEvent::EndElement { name } => {
|
||||
if parser.depth() == starting_depth-1 { break; }
|
||||
},
|
||||
XmlEvent::EndDocument => {
|
||||
Err(ParseProjectError::EndOfDocument)?
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_err_continue {
|
||||
($res:expr) => {
|
||||
match $res {
|
||||
Ok(val) => val,
|
||||
Err(e) => { continue; }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_opt_continue {
|
||||
($res:expr) => {
|
||||
match $res {
|
||||
Some(val) => val,
|
||||
None => { continue; }
|
||||
}
|
||||
};
|
||||
}
|
29
src/main.rs
Normal file
29
src/main.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use magicdraw_parser::parse_project;
|
||||
use yew::prelude::*;
|
||||
use std::fs::File;
|
||||
use anyhow::Result;
|
||||
|
||||
mod magicdraw_parser;
|
||||
|
||||
// TODO: Make this work with enumation lookup tables
|
||||
|
||||
#[function_component]
|
||||
fn App() -> Html {
|
||||
html! {
|
||||
<main>
|
||||
<img class="logo" src="https://yew.rs/img/logo.png" alt="Yew logo" />
|
||||
<h1>{ "Hello World!" }</h1>
|
||||
<span class="subtitle">{ "from Yew with " }<i class="heart" /></span>
|
||||
</main>
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let f = File::open("example.mdzip").unwrap();
|
||||
|
||||
let collections = parse_project(f)?;
|
||||
dbg!(collections);
|
||||
|
||||
// yew::Renderer::<App>::new().render();
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user