Merge pull request 'push-txpxkkntoxrz' (#10) from push-txpxkkntoxrz into main

Reviewed-on: #10
This commit was merged in pull request #10.
This commit is contained in:
2025-10-05 21:44:56 +02:00
1256 changed files with 547930 additions and 9 deletions

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@ xxx
**/.pmomusic_covers/**
**/.DS_Strore/**
**/.DS_Strore
/target/
.pmomusic_covers
C/src/soxr-0.1.3/Release/tests
**/Release/

678
Cargo.lock generated Normal file
View File

@@ -0,0 +1,678 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "PMOMusic"
version = "0.1.0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "cc"
version = "1.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
[[package]]
name = "chrono"
version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[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 = "find-msvc-tools"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "iana-time-zone"
version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "icu_collections"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
dependencies = [
"displaydoc",
"potential_utf",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
dependencies = [
"displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
[[package]]
name = "icu_properties"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"potential_utf",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
[[package]]
name = "icu_provider"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
dependencies = [
"displaydoc",
"icu_locale_core",
"stable_deref_trait",
"tinystr",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
name = "js-sys"
version = "0.3.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "litemap"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pmoupnp"
version = "0.1.0"
dependencies = [
"base64",
"chrono",
"hex",
"thiserror",
"url",
"uuid",
"xmltree",
]
[[package]]
name = "potential_utf"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
dependencies = [
"zerovec",
]
[[package]]
name = "proc-macro2"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "serde"
version = "1.0.225"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.225"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.225"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thiserror"
version = "2.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinystr"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "unicode-ident"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "url"
version = "2.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "uuid"
version = "1.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
[[package]]
name = "windows-result"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
dependencies = [
"windows-link",
]
[[package]]
name = "writeable"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
[[package]]
name = "xml-rs"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7"
[[package]]
name = "xmltree"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b619f8c85654798007fb10afa5125590b43b088c225a25fc2fec100a9fad0fc6"
dependencies = [
"xml-rs",
]
[[package]]
name = "yoke"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerofrom"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerotrie"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

3
Cargo.toml Normal file
View File

@@ -0,0 +1,3 @@
[workspace]
resolver = "3"
members = ["PMOMusic", "pmoupnp"]

6
PMOMusic/Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "PMOMusic"
version = "0.1.0"
edition = "2024"
[dependencies]

3
PMOMusic/src/main.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@@ -1,9 +0,0 @@
## Installing documentation system Doc-Gen
https://github.com/fynnfluegge/doc-comments-ai
for f in upnp/*.go ; do
dcai/bin/aicomment --ollama-model deepseek-coder:33b-instruct $f
done

100
Readme.md Normal file
View File

@@ -0,0 +1,100 @@
# Développement de l'application PMOMusic en RUST
## Création de la structure
```bash
mkdir pizzicato
cd pizzicato
jj git init
touch Readme.md
```
Maintenant on peu créer l'application PMOMusic
```bash
cargo new PMOMusic
```
On ajoute un fichier `Cargo.toml` décrivant le workspace pizzicato qui ne contient que notre nouvelle application
```
[workspace]
members = ["PMOMusic"]
```
On crée le package `pmoupnp`
```bash
cargo new pmoupnp --lib
```
Cela modifie automatiquement le fichier `Cargo.toml` créé juste avant.
Dans ce package un sous module `statevariable`
```bash
cd pmoupnp/src
mkdir statevariable
```
# Petite expériences jujutsu
- Je veux voir l'historique
```bash
jj log
````
```
@ lkmlpmnk eric@coissac.eu 2025-09-12 09:48:38 a27b6a9a
│ On commence les states variables
○ mzvokmpk eric@coissac.eu 2025-09-12 09:32:27 926827f3
│ Retire le répertoir target du suivi
○ skknrvut eric@coissac.eu 2025-09-12 09:05:27 cbad5c34
│ Initialisation des l'arborescence de répertoires
◆ zzzzzzzz root() 00000000
```
- Je veux me mettre dans un commit:
```bash
jj edit mzvokmpk
```
je veux créer un nouveau commit à la suite d'un autre et m'y placer
```bash
jj new mzvokmpk
```
`mzvokmpk` peut être `@` pour dans le commit courant ou `@-` pour dans le parent
- je veux arreter de suivre
- un fichier
```bash
jj file untrack <filename>
```
- un répertoire
```bash
find dirname -type f -exec jj file untrack {} \;
```
Dans tous les cas ne pas oublier d'inscrire le fichier ou le repertoire dans le `.gitignore`
- je veux déplacer un commit comme un sous commit d'un aute
```bash
jj rebase -d destination -r source
```
eventuellement faire un
```bash
jj resolve --all
jj rebase --continue
```
pour résoudre les conflits

13
pmoupnp/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
[package]
name = "pmoupnp"
version = "0.1.0"
edition = "2024"
[dependencies]
chrono = "0.4.42"
url = "2.5.7"
uuid = "1.18.1"
hex = "0.4.3"
base64 = "0.22.1"
thiserror = "2.0.16"
xmltree = "0.11.0"

14
pmoupnp/src/lib.rs Normal file
View File

@@ -0,0 +1,14 @@
mod object_trait;
pub mod variable_types;
pub mod state_variables;
pub mod value_ranges;
pub use crate::object_trait::UpnpObject;
#[derive(Clone)]
pub struct UpnpObjectType {
name: String,
object_type: String,
}

View File

@@ -0,0 +1,39 @@
use xmltree::{Element, EmitterConfig};
use crate::UpnpObjectType;
pub trait UpnpObject {
fn as_upnp_object_type(&self) -> &UpnpObjectType;
fn to_xml_element(&self) -> Element;
fn get_name(&self)-> &String {
return &self.as_upnp_object_type().name;
}
fn get_object_type(&self) -> &String {
&self.as_upnp_object_type().object_type
}
fn to_xml(&self) -> String {
let elem = self.to_xml_element();
// Configurer l'indentation
let config = EmitterConfig::new()
.perform_indent(true)
.indent_string(" "); // 2 espaces
// Sérialiser dans un buffer
let mut buf = Vec::new();
// écrire l'élément
elem.write_with_config(&mut buf, config)
.expect("Failed to write XML");
// Préfixer avec l'en-tête XML
let mut xml_string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".to_string();
xml_string.push_str(&String::from_utf8(buf).expect("Invalid UTF-8"));
xml_string
}
}

View File

@@ -0,0 +1,28 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum StateVariableError {
#[error("Conversion error: {0}")]
ConversionError(String),
#[error("Validation error: {0}")]
ValidationError(String),
#[error("Range error: {0}")]
RangeError(String),
#[error("Type error: {0}")]
TypeError(String),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Event condition error: {0}")]
EventConditionError(String),
#[error("Arithmetic error: {0}")]
ArithmeticError(String),
#[error("Unknown error: {0}")]
Unknown(String),
}

View File

@@ -0,0 +1,58 @@
use chrono::{DateTime, Utc};
use xmltree::Element;
use crate::{
state_variables::{StateVarInstance, StateVariable, UpnpVariable},
variable_types::StateValue,
UpnpObject,
UpnpObjectType
};
impl UpnpVariable for StateVarInstance {
fn get_definition(&self) -> &StateVariable {
return &self.definition;
}
}
impl UpnpObject for StateVarInstance {
fn as_upnp_object_type(&self) -> &UpnpObjectType {
return &self.object;
}
fn to_xml_element(&self) -> Element {
self.get_definition().to_xml_element()
}
}
impl StateVarInstance {
pub fn new(from: &StateVariable) -> Self {
Self {
object: UpnpObjectType {
name: from.object.name.clone(),
object_type: "StateVarInstance".to_string(),
},
definition: from.clone(),
value: from.get_default(),
old_value: from.get_default(),
last_modified: Utc::now(),
last_notification: Utc::now()
}
}
pub fn set_value(&mut self, new_value: StateValue) {
self.old_value = self.value.clone();
self.value = new_value;
self.last_modified = Utc::now(); // mise à jour automatique
}
/// Accès à la valeur
pub fn value(&self) -> &StateValue {
&self.value
}
/// Accès au timestamp
pub fn last_modified(&self) -> DateTime<Utc> {
self.last_modified
}
}

View File

@@ -0,0 +1,47 @@
mod errors;
mod variable_trait;
mod variable_methods;
mod instance_methods;
use std::{collections::HashMap, sync::{Arc, RwLock}};
use chrono::{DateTime, Utc};
pub use errors::{StateVariableError};
pub use crate::state_variables::variable_trait::UpnpVariable;
use crate::{value_ranges::ValueRange, variable_types::{StateValue, StateVarType}, UpnpObjectType};
/// Type pour les fonctions de condition d'événement
pub type StateConditionFunc = Arc<dyn Fn(&StateVarInstance) -> bool + Send + Sync>;
/// Type pour les fonctions de parsing de valeurs depuis des chaînes
pub type StringValueParser = Arc<dyn Fn(&str) -> Result<StateValue, StateVariableError> + Send + Sync>;
/// Type pour les fonctions de sérialisation de valeurs vers des chaînes
pub type ValueSerializer = Arc<dyn Fn(&StateValue) -> Result<String, StateVariableError> + Send + Sync>;
pub struct StateVariable {
object: UpnpObjectType,
value_type: StateVarType,
step: Option<StateValue>,
modifiable: bool,
event_conditions: Arc<RwLock<HashMap<String, StateConditionFunc>>>,
description: String,
default_value: Option<StateValue>,
value_range: Option<ValueRange>,
allowed_values: Arc<RwLock<Vec<StateValue>>>,
send_events: bool,
parse: Option<StringValueParser>,
marshal: Option<ValueSerializer>,
}
pub struct StateVarInstance {
object: UpnpObjectType,
definition: StateVariable,
value: StateValue,
old_value: StateValue,
last_modified: DateTime<Utc>,
last_notification: DateTime<Utc>,
}

View File

@@ -0,0 +1,353 @@
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
use xmltree::{Element, XMLNode};
use crate::{
UpnpObject, UpnpObjectType,
state_variables::{
StateConditionFunc, StateVariable, StringValueParser, ValueSerializer,
variable_trait::UpnpVariable,
},
value_ranges::ValueRange,
variable_types::{StateValue, StateValueError, StateVarType, UpnpVarType},
};
impl UpnpObject for StateVariable {
fn as_upnp_object_type(&self) -> &UpnpObjectType {
return &self.object;
}
fn to_xml_element(&self) -> Element {
// Création de l'élément racine <stateVariable>
let mut root = Element::new("stateVariable");
root.attributes.insert(
"sendEvents".to_string(),
if self.send_events { "yes" } else { "no" }.to_string(),
);
// <name>
let mut name_elem = Element::new("name");
name_elem
.children
.push(XMLNode::Text(self.get_name().clone()));
// <dataType>
let mut datatype_elem = Element::new("dataType");
datatype_elem
.children
.push(XMLNode::Text(self.value_type.to_string())); // StateVarType doit impl Display
// <defaultValue> si défini
if let Some(default) = &self.default_value {
let mut def_elem = Element::new("defaultValue");
def_elem.children.push(XMLNode::Text(default.to_string()));
root.children.push(XMLNode::Element(def_elem));
}
// <allowedValueList> si défini
if let Ok(av) = self.allowed_values.read() {
if !av.is_empty() {
let mut list_elem = Element::new("allowedValueList");
for val in av.iter() {
let mut val_elem = Element::new("allowedValue");
val_elem.children.push(XMLNode::Text(val.to_string()));
list_elem.children.push(XMLNode::Element(val_elem));
}
root.children.push(XMLNode::Element(list_elem));
}
}
// <allowedValueRange> si défini
if let Some(range) = &self.value_range {
let mut range_elem = Element::new("allowedValueRange");
let mut min_elem = Element::new("minimum");
min_elem.children.push(XMLNode::Text(range.get_minimum().to_string()));
range_elem.children.push(XMLNode::Element(min_elem));
let mut max_elem = Element::new("maximum");
max_elem.children.push(XMLNode::Text(range.get_maximum().to_string()));
range_elem.children.push(XMLNode::Element(max_elem));
if let Some(step) = &self.step {
let mut step_elem = Element::new("step");
step_elem.children.push(XMLNode::Text(step.to_string()));
range_elem.children.push(XMLNode::Element(step_elem));
}
root.children.push(XMLNode::Element(range_elem));
}
// Ajouter les enfants communs
root.children.push(XMLNode::Element(name_elem));
root.children.push(XMLNode::Element(datatype_elem));
root
}
}
impl Clone for StateVariable {
fn clone(&self) -> Self {
// clone safe des structures protégées par RwLock en prenant un read lock
let event_conditions_clone = {
// si le lock est "poisoned" on panic - tu peux adapter la gestion si tu veux
let guard = self
.event_conditions
.read()
.expect("RwLock poisoned during clone");
// nécessite que Key: Clone, Value: Clone
Arc::new(RwLock::new(guard.clone()))
};
let allowed_values_clone = {
let guard = self
.allowed_values
.read()
.expect("RwLock poisoned during clone");
Arc::new(RwLock::new(guard.clone()))
};
Self {
object: self.object.clone(),
value_type: self.value_type.clone(),
step: self.step.clone(),
modifiable: self.modifiable,
event_conditions: event_conditions_clone,
description: self.description.clone(),
default_value: self.default_value.clone(),
value_range: self.value_range.clone(),
allowed_values: allowed_values_clone,
send_events: self.send_events,
// parse et marshal sont typiquement des Arc<dyn ...> — on clone l'Arc (shallow).
// Deep-cloner une closure ou un trait-objet n'est pas possible en général.
parse: self.parse.clone(),
marshal: self.marshal.clone(),
}
}
}
impl UpnpVarType for StateVariable {
fn as_state_var_type(&self) -> StateVarType {
self.value_type // utilise ton From<&StateValue> existant
}
}
impl UpnpVariable for StateVariable {
fn get_definition(&self) -> &StateVariable {
return self;
}
}
impl StateVariable {
pub fn new(vartype: StateVarType, name: String) -> StateVariable {
Self {
object: UpnpObjectType {
name,
object_type: "StateVariable".to_string(),
},
value_type: vartype.clone(),
step: None,
modifiable: true,
event_conditions: Arc::new(RwLock::new(HashMap::new())),
description: "".to_string(),
default_value: None,
value_range: None,
allowed_values: Arc::new(RwLock::new(Vec::new())),
send_events: false,
parse: None,
marshal: None,
}
}
pub fn set_step(&mut self, step: StateValue) -> Result<(), StateValueError> {
if self.as_state_var_type() != step.as_state_var_type() {
return Err(StateValueError::TypeError("Bad step type".to_string()));
}
self.step = Some(step);
Ok(())
}
pub fn set_range(&mut self, min: &StateValue, max: &StateValue) -> Result<(), StateValueError> {
if self.as_state_var_type() != min.as_state_var_type() {
return Err(StateValueError::TypeError("Bad range type".to_string()));
}
let range = ValueRange::new(min, max)?; // ? propage l'erreur si elle existe
self.value_range = Some(range);
Ok(())
}
pub fn update_minimum(&mut self, min: &StateValue) -> Result<(), StateValueError> {
if !self.has_range() {
return Err(StateValueError::RangeError(
"No range specified for this variable".to_string(),
));
}
if self
.value_range
.as_ref()
.expect("Range is not defined")
.as_state_var_type()
!= min.as_state_var_type()
{
return Err(StateValueError::TypeError(
"new minimum is not the same than state variable".to_string(),
));
}
self.value_range
.as_mut()
.expect("Range is not defined")
.set_minimum(min);
return Ok(());
}
pub fn update_maximum(&mut self, min: &StateValue) -> Result<(), StateValueError> {
if !self.has_range() {
return Err(StateValueError::RangeError(
"No range specified for this variable".to_string(),
));
}
if self
.value_range
.as_ref()
.expect("Range is not defined")
.as_state_var_type()
!= min.as_state_var_type()
{
return Err(StateValueError::TypeError(
"new minimum is not the same than state variable".to_string(),
));
}
self.value_range
.as_mut()
.expect("Range is not defined")
.set_maximum(min);
return Ok(());
}
pub fn get_range(&self) -> Option<&ValueRange> {
return self.value_range.as_ref();
}
pub fn set_modifiable(&mut self) {
self.modifiable = true;
}
pub fn set_not_modifiable(&mut self) {
self.modifiable = false;
}
pub fn add_event_condition(&self, name: String, func: StateConditionFunc) {
// on lock en écriture
let mut guard = self.event_conditions.write().unwrap();
guard.insert(name, func);
// le lock est automatiquement relâché ici (RAII)
}
pub fn remove_event_condition(&self, name: &str) {
let mut guard = self.event_conditions.write().unwrap();
guard.remove(name);
}
pub fn clear_event_conditions(&mut self) {
let mut guard = self.event_conditions.write().unwrap();
guard.clear()
}
pub fn set_description(&mut self, description: String) {
self.description = description;
}
pub fn set_default(&mut self, value: StateValue) -> Result<(), StateValueError> {
if self.as_state_var_type() != value.as_state_var_type() {
return Err(StateValueError::TypeError(
"value does not have the right type".to_string(),
));
}
self.default_value = Some(value.clone());
return Ok(());
}
pub fn unset_default(&mut self) {
self.default_value = None;
}
pub fn extend_allowed_values(&mut self, values: &[StateValue]) -> Result<(), StateValueError> {
let mut av = self
.allowed_values
.write()
.map_err(|_| StateValueError::TypeError("Lock poisoned".to_string()))?;
for v in values {
if self.as_state_var_type() == v.as_state_var_type() {
av.push(v.clone());
} else {
return Err(StateValueError::TypeError(
"new allowed value does not have the right type".to_string(),
));
}
}
Ok(())
}
pub fn push_allowed_value(&mut self, value: &StateValue) -> Result<(), StateValueError> {
let mut av = self
.allowed_values
.write()
.map_err(|_| StateValueError::TypeError("Lock poisoned".to_string()))?;
if self.as_state_var_type() == value.as_state_var_type() {
av.push(value.clone());
} else {
return Err(StateValueError::TypeError(
"new allowed value does not have the right type".to_string(),
));
}
return Ok(());
}
pub fn set_send_notification(&mut self) {
self.send_events = true;
}
pub fn unset_send_notification(&mut self) {
self.send_events = false;
}
pub fn set_value_parseur(&mut self, parser: StringValueParser) -> Result<(), StateValueError> {
if self.as_state_var_type() == StateVarType::String {
self.parse = Some(parser);
return Ok(());
}
return Err(StateValueError::TypeError(
"Only String variables can have a parser".to_string(),
));
}
pub fn unset_value_parser(&mut self) {
self.parse = None;
}
pub fn set_value_marshaler(
&mut self,
marshaler: ValueSerializer,
) -> Result<(), StateValueError> {
if self.as_state_var_type() == StateVarType::String {
self.marshal = Some(marshaler);
return Ok(());
}
return Err(StateValueError::TypeError(
"Only String variables can have a marshaler".to_string(),
));
}
pub fn unset_value_marshaler(&mut self) {
self.marshal = None;
}
}

View File

@@ -0,0 +1,73 @@
use crate::{
state_variables::StateVariable,
variable_types::{StateValue, UpnpVarType},
};
pub trait UpnpVariable {
fn get_definition(&self) -> &StateVariable;
fn has_step(&self) -> bool {
return self.get_definition().step.is_some();
}
fn get_step(&self) -> Option<StateValue> {
return self.get_definition().step.clone();
}
fn has_range(&self) -> bool {
return self.get_definition().value_range.is_some();
}
fn is_modifiable(&self) -> bool {
return self.get_definition().modifiable;
}
fn has_event_conditions(&self) -> bool {
return self.get_definition().event_conditions.read().unwrap().len() > 0;
}
fn has_event_condition(&self, name: &String) -> bool {
let guard = self.get_definition().event_conditions.read().unwrap();
return guard.contains_key(name);
}
fn has_description(&self) -> bool {
return !String::is_empty(&self.get_definition().description);
}
fn get_description(&self) -> String {
return self.get_definition().description.clone();
}
fn has_default(&self) -> bool {
return self.get_definition().default_value.is_some();
}
fn get_default(&self) -> StateValue {
self.get_definition()
.default_value
.clone()
.unwrap_or_else(|| self.get_definition().as_state_var_type().default_value())
}
fn has_allowed_values(&self) -> bool {
return self.get_definition().allowed_values.read().unwrap().len() > 0;
}
fn is_an_allowed_values(&self, value: &StateValue) -> bool {
let guard = self.get_definition().allowed_values.read().unwrap();
return guard.contains(value);
}
fn is_sending_notification(&self) -> bool {
self.get_definition().send_events
}
fn has_value_parser(&self) -> bool {
self.get_definition().parse.is_some()
}
fn has_value_marshaler(&self) -> bool {
self.get_definition().marshal.is_some()
}
}

View File

@@ -0,0 +1,69 @@
use std::cmp::Ordering;
use crate::{
value_ranges::ValueRange,
variable_types::{StateValue, StateValueError, StateVarType, UpnpVarType},
};
impl UpnpVarType for ValueRange {
fn as_state_var_type(&self) -> StateVarType {
self.min.as_state_var_type() // utilise ton From<&StateValue> existant
}
}
impl ValueRange {
pub fn new(min: &StateValue, max: &StateValue) -> Result<Self, StateValueError> {
if min.as_state_var_type() != max.as_state_var_type() {
return Err(StateValueError::TypeError(
"min and max do not belong the same time".to_string(),
));
}
// Vérifier que min <= max
if let Some(cmp) = min.partial_cmp(max) {
if cmp == Ordering::Greater {
return Err(StateValueError::RangeError(
"Minimum cannot be greater than maximum".to_string(),
));
}
}
Ok(Self {
min: min.clone(),
max: max.clone(),
})
}
pub fn get_minimum(self: &ValueRange) -> StateValue {
return self.min.clone();
}
pub fn set_minimum(&mut self, value: &StateValue) {
self.min = value.clone()
}
pub fn get_maximum(self: &ValueRange) -> StateValue {
return self.max.clone();
}
pub fn set_maximum(&mut self, value: &StateValue) {
self.max = value.clone()
}
pub fn is_in_range(&self, value: &StateValue) -> bool {
if self.as_state_var_type() == value.as_state_var_type()
&& let Some(cmp) = self.min.partial_cmp(value)
{
if cmp == Ordering::Greater {
return false;
}
if let Some(cmp2) = self.max.partial_cmp(value) {
if cmp2 == Ordering::Less {
return false;
}
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,10 @@
mod methods;
use crate::variable_types::StateValue;
#[derive(Debug, Clone)]
pub struct ValueRange {
min: StateValue,
max: StateValue,
}

View File

@@ -0,0 +1,37 @@
use crate::variable_types::{StateValue, StateVarType, StateValueError};
use std::convert::TryFrom;
impl StateValue {
pub fn try_cast(&self, target: StateVarType) -> Result<StateValue, StateValueError> {
let source = StateVarType::from(self);
// Identité (même type)
if source == target {
return Ok(self.clone());
}
match (self, target) {
(val, StateVarType::String) => Ok(StateValue::String(val.to_string())),
(_,StateVarType::UI1) => Ok(StateValue::UI1(u8::try_from(self)?)),
(_,StateVarType::UI2) => Ok(StateValue::UI2(u16::try_from(self)?)),
(_,StateVarType::UI4) => Ok(StateValue::UI4(u32::try_from(self)?)),
(_,StateVarType::I1) => Ok(StateValue::I1(i8::try_from(self)?)),
(_,StateVarType::I2) => Ok(StateValue::I2(i16::try_from(self)?)),
(_,StateVarType::I4) => Ok(StateValue::I4(i32::try_from(self)?)),
(_,StateVarType::Int) => Ok(StateValue::Int(i32::try_from(self)?)),
(_,StateVarType::R8) => Ok(StateValue::R8(f64::try_from(self)?)),
(_,StateVarType::Number) => Ok(StateValue::Number(f64::try_from(self)?)),
(_,StateVarType::Fixed14_4) => Ok(StateValue::Fixed14_4(f64::try_from(self)?)),
(_,StateVarType::R4) => Ok(StateValue::R4(f32::try_from(self)?)),
// --- Pas encore implémenté pour les autres types ---
(val, target) => Err(StateValueError::TypeError(format!(
"Cannot cast {:?} to {:?}",
val, target
))),
}
}
}

View File

@@ -0,0 +1,43 @@
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveTime};
use url::Url;
use uuid::Uuid;
use crate::variable_types::{StateValue, StateVarType};
impl StateVarType {
pub fn default_value(&self) -> StateValue {
match self {
StateVarType::UI1 => StateValue::UI1(0),
StateVarType::UI2 => StateValue::UI2(0),
StateVarType::UI4 => StateValue::UI4(0),
StateVarType::I1 => StateValue::I1(0),
StateVarType::I2 => StateValue::I2(0),
StateVarType::I4 => StateValue::I4(0),
StateVarType::Int => StateValue::Int(0),
StateVarType::R4 => StateValue::R4(0.0),
StateVarType::R8 => StateValue::R8(0.0),
StateVarType::Number => StateValue::Number(0.0),
StateVarType::Fixed14_4 => StateValue::Fixed14_4(0.0),
StateVarType::Char => StateValue::Char('\0'),
StateVarType::String => StateValue::String(String::new()),
StateVarType::Boolean => StateValue::Boolean(false),
StateVarType::BinBase64 => StateValue::BinBase64(String::new()),
StateVarType::BinHex => StateValue::BinHex(String::new()),
StateVarType::Date => StateValue::Date(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()),
StateVarType::DateTime => StateValue::DateTime(DateTime::from_timestamp(0, 0).unwrap().naive_utc().into()),
StateVarType::DateTimeTZ => StateValue::DateTimeTZ(
DateTime::from_naive_utc_and_offset(
DateTime::from_timestamp(0, 0).unwrap().naive_utc(),
FixedOffset::east_opt(0).unwrap())
),
StateVarType::Time => StateValue::Time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()),
StateVarType::TimeTZ => StateValue::TimeTZ(
DateTime::from_naive_utc_and_offset(
DateTime::from_timestamp(0, 0).unwrap().naive_utc(),
FixedOffset::east_opt(0).unwrap())
),
StateVarType::UUID => StateValue::UUID(Uuid::nil()),
StateVarType::URI => StateValue::URI(Url::parse("http://localhost").unwrap()),
}
}
}

View File

@@ -0,0 +1,35 @@
use std::fmt;
use crate::variable_types::StateVarType;
impl fmt::Display for StateVarType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
StateVarType::UI1 => "ui1",
StateVarType::UI2 => "ui2",
StateVarType::UI4 => "ui4",
StateVarType::I1 => "i1",
StateVarType::I2 => "i2",
StateVarType::I4 => "i4",
StateVarType::Int => "int",
StateVarType::R4 => "r4",
StateVarType::R8 => "r8",
StateVarType::Number => "number",
StateVarType::Fixed14_4 => "fixed.14.4",
StateVarType::Char => "char",
StateVarType::String => "string",
StateVarType::Boolean => "boolean",
StateVarType::BinBase64 => "bin.base64",
StateVarType::BinHex => "bin.hex",
StateVarType::Date => "date",
StateVarType::DateTime => "dateTime",
StateVarType::DateTimeTZ => "dateTime.tz",
StateVarType::Time => "time",
StateVarType::TimeTZ => "time.tz",
StateVarType::UUID => "uuid",
StateVarType::URI => "uri",
};
write!(f, "{}", s)
}
}

View File

@@ -0,0 +1,45 @@
use std::fmt;
use base64::engine::general_purpose;
use base64::Engine;
use crate::variable_types::StateValue;
impl fmt::Display for StateValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
// Numériques
StateValue::UI1(v) => write!(f, "{}", v),
StateValue::UI2(v) => write!(f, "{}", v),
StateValue::UI4(v) => write!(f, "{}", v),
StateValue::I1(v) => write!(f, "{}", v),
StateValue::I2(v) => write!(f, "{}", v),
StateValue::I4(v) => write!(f, "{}", v),
StateValue::Int(v) => write!(f, "{}", v),
StateValue::R4(v) => write!(f, "{}", v),
StateValue::R8(v) => write!(f, "{}", v),
StateValue::Number(v) => write!(f, "{}", v),
StateValue::Fixed14_4(v) => write!(f, "{}", v),
// Types déjà Display
StateValue::Char(v) => write!(f, "{}", v),
StateValue::String(v) => write!(f, "{}", v),
StateValue::UUID(v) => write!(f, "{}", v),
StateValue::URI(v) => write!(f, "{}", v),
// Booléen : 1 ou 0
StateValue::Boolean(v) => write!(f, "{}", if *v { "1" } else { "0" }),
// Encodages binaires
StateValue::BinBase64(v) => write!(f, "{}", general_purpose::URL_SAFE.encode(v)),
StateValue::BinHex(v) => write!(f, "{}", hex::encode(v)),
// Dates et temps
StateValue::Date(v) => write!(f, "{}", v.format("%Y-%m-%d")),
StateValue::DateTime(v) => write!(f, "{}", v.format("%Y-%m-%dT%H:%M:%S")),
StateValue::DateTimeTZ(v) => write!(f, "{}", v.to_rfc3339()),
StateValue::Time(v) => write!(f, "{}", v.format("%H:%M:%S")),
StateValue::TimeTZ(v) => write!(f, "{}", v.format("%H:%M:%S%z")),
}
}
}

View File

@@ -0,0 +1,28 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum StateValueError {
#[error("Conversion error: {0}")]
ConversionError(String),
#[error("Validation error: {0}")]
ValidationError(String),
#[error("Range error: {0}")]
RangeError(String),
#[error("Type error: {0}")]
TypeError(String),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Event condition error: {0}")]
EventConditionError(String),
#[error("Arithmetic error: {0}")]
ArithmeticError(String),
#[error("Unknown error: {0}")]
Unknown(String),
}

View File

@@ -0,0 +1,36 @@
use std::str::FromStr;
use crate::variable_types::StateVarType;
impl FromStr for StateVarType {
type Err = String; // Type d'erreur personnalisé
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"ui1" => Ok(StateVarType::UI1),
"ui2" => Ok(StateVarType::UI2),
"ui4" => Ok(StateVarType::UI4),
"i1" => Ok(StateVarType::I1),
"i2" => Ok(StateVarType::I2),
"i4" => Ok(StateVarType::I4),
"int" => Ok(StateVarType::Int),
"r4" => Ok(StateVarType::R4),
"r8" => Ok(StateVarType::R8),
"number" => Ok(StateVarType::Number),
"fixed.14.4" => Ok(StateVarType::Fixed14_4),
"char" => Ok(StateVarType::Char),
"string" => Ok(StateVarType::String),
"boolean" => Ok(StateVarType::Boolean),
"bin.base64" => Ok(StateVarType::BinBase64),
"bin.hex" => Ok(StateVarType::BinHex),
"date" => Ok(StateVarType::Date),
"datetime" => Ok(StateVarType::DateTime),
"datetime.tz" => Ok(StateVarType::DateTimeTZ),
"time" => Ok(StateVarType::Time),
"time.tz" => Ok(StateVarType::TimeTZ),
"uuid" => Ok(StateVarType::UUID),
"uri" => Ok(StateVarType::URI),
_ => Err(format!("Type inconnu: {}", s)),
}
}
}

View File

@@ -0,0 +1,96 @@
mod type_methods;
mod value_methods;
mod type_trait;
mod value_trait;
mod fromstr;
mod cast;
mod display_type;
mod display_value;
mod default_value;
mod errors;
mod values_from_type;
mod values_from_u8;
mod values_from_u16;
mod values_from_u32;
mod values_from_i8;
mod values_from_i16;
mod values_from_i32;
mod values_from_i64;
mod values_from_f32;
mod values_from_f64;
mod values_from_uri;
mod values_from_uuid;
mod values_from_naivedate;
mod values_from_naivedatetime;
mod values_from_naivetime;
mod values_from_datetime;
mod values_from_vec_u8;
use std::fmt::{Debug};
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
use url::Url;
use uuid::Uuid;
pub use errors::StateValueError;
pub use type_trait::UpnpVarType;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StateVarType {
UI1, // Unsigned 8-bit integer
UI2, // Unsigned 16-bit integer
UI4, // Unsigned 32-bit integer
I1, // Signed 8-bit integer
I2, // Signed 16-bit integer
I4, // Signed 32-bit integer
Int, // Synonymous with i4
R4, // 32-bit floating point
R8, // 64-bit floating point
Number, // Synonymous with r8
Fixed14_4, // Fixed-point decimal
Char, // Single Unicode character
String, // Character string
Boolean, // Boolean value
BinBase64, // Base64-encoded binary
BinHex, // Hex-encoded binary
Date, // Date (YYYY-MM-DD)
DateTime, // DateTime without timezone
DateTimeTZ, // DateTime with timezone
Time, // Time without timezone
TimeTZ, // Time with timezone
UUID, // Universally unique identifier
URI, // Uniform Resource Identifier
}
#[derive(Debug, Clone)]
pub enum StateValue {
UI1(u8),
UI2(u16),
UI4(u32),
I1(i8),
I2(i16),
I4(i32),
Int(i32),
R4(f32),
R8(f64),
Number(f64),
Fixed14_4(f64),
Char(char),
String(String),
Boolean(bool),
BinBase64(String),
BinHex(String),
Date(NaiveDate),
DateTime(NaiveDateTime),
DateTimeTZ(DateTime<FixedOffset>),
Time(NaiveTime),
TimeTZ(DateTime<FixedOffset>),
UUID(Uuid),
URI(Url),
}

View File

@@ -0,0 +1,109 @@
use crate::variable_types::{type_trait::UpnpVarType, StateVarType};
impl UpnpVarType for StateVarType {
fn as_state_var_type(&self) -> StateVarType {
*self
}
fn bit_size(&self) -> Option<usize> {
match self {
StateVarType::UI1 | StateVarType::I1 => Some(8),
StateVarType::UI2 | StateVarType::I2 => Some(16),
StateVarType::UI4 | StateVarType::I4 | StateVarType::Int | StateVarType::R4 => Some(32),
StateVarType::R8 | StateVarType::Number | StateVarType::Fixed14_4 => Some(64),
_ => None,
}
}
fn is_numeric(&self) -> bool {
matches!(
self,
StateVarType::UI1
| StateVarType::UI2
| StateVarType::UI4
| StateVarType::I1
| StateVarType::I2
| StateVarType::I4
| StateVarType::Int
| StateVarType::R4
| StateVarType::R8
| StateVarType::Number
| StateVarType::Fixed14_4
)
}
fn is_integer(&self) -> bool {
matches!(
self,
StateVarType::UI1
| StateVarType::UI2
| StateVarType::UI4
| StateVarType::I1
| StateVarType::I2
| StateVarType::I4
| StateVarType::Int
)
}
fn is_signed_int(&self) -> bool {
matches!(
self,
StateVarType::I1 | StateVarType::I2 | StateVarType::I4 | StateVarType::Int
)
}
fn is_unsigned_int(&self) -> bool {
matches!(
self,
StateVarType::UI1 | StateVarType::UI2 | StateVarType::UI4
)
}
fn is_float(&self) -> bool {
matches!(
self,
StateVarType::R4
| StateVarType::R8
| StateVarType::Number
| StateVarType::Fixed14_4
)
}
fn is_bool(&self) -> bool {
matches!(self, StateVarType::Boolean)
}
fn is_string(&self) -> bool {
matches!(self, StateVarType::String
| StateVarType::Char
| StateVarType::BinHex
| StateVarType::BinBase64)
}
fn is_time(&self) -> bool {
matches!(
self,
StateVarType::Date
| StateVarType::DateTime
| StateVarType::DateTimeTZ
| StateVarType::Time
| StateVarType::TimeTZ
)
}
fn is_uuid(&self) -> bool {
matches!(self, StateVarType::UUID)
}
fn is_uri(&self) -> bool {
matches!(self, StateVarType::URI)
}
fn is_binary(&self) -> bool {
matches!(self, StateVarType::BinBase64 | StateVarType::BinHex)
}
fn is_comparable(&self) -> bool {
!self.is_binary()
}
}

View File

@@ -0,0 +1,57 @@
use crate::variable_types::StateVarType;
pub trait UpnpVarType {
fn as_state_var_type(&self) -> StateVarType;
fn bit_size(&self) -> Option<usize> {
self.as_state_var_type().bit_size()
}
fn is_numeric(&self) -> bool {
self.as_state_var_type().is_numeric()
}
fn is_integer(&self) -> bool {
self.as_state_var_type().is_integer()
}
fn is_signed_int(&self) -> bool {
self.as_state_var_type().is_signed_int()
}
fn is_unsigned_int(&self) -> bool {
self.as_state_var_type().is_unsigned_int()
}
fn is_float(&self) -> bool {
self.as_state_var_type().is_float()
}
fn is_bool(&self) -> bool {
self.as_state_var_type().is_bool()
}
fn is_string(&self) -> bool {
self.as_state_var_type().is_string()
}
fn is_time(&self) -> bool {
self.as_state_var_type().is_time()
}
fn is_uuid(&self) -> bool {
self.as_state_var_type().is_uuid()
}
fn is_uri(&self) -> bool {
self.as_state_var_type().is_uri()
}
fn is_binary(&self) -> bool {
self.as_state_var_type().is_binary()
}
fn is_comparable(&self) -> bool {
self.as_state_var_type().is_comparable()
}
}

View File

@@ -0,0 +1,89 @@
use std::cmp::Ordering;
use crate::variable_types::{StateValue, StateVarType, type_trait::UpnpVarType};
impl UpnpVarType for StateValue {
fn as_state_var_type(&self) -> StateVarType {
StateVarType::from(self) // utilise ton From<&StateValue> existant
}
}
impl PartialEq for StateValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(a, b) if a.is_integer() && b.is_integer() => {
if let (Ok(ia), Ok(ib)) = (i64::try_from(a), i64::try_from(b)) {
return ia == ib;
};
return false;
}
(a, b) if a.is_float() && b.is_float() => {
if let (Ok(a), Ok(b)) = (f64::try_from(self), f64::try_from(other)) {
return a == b; // NaN respecte la sémantique IEEE (NaN != NaN)
}
return false;
}
(a, b) if a.is_string() && b.is_string() => {
let (a, b) = (self.to_string(), other.to_string());
return a == b; // NaN respecte la sémantique IEEE (NaN != NaN)
}
(StateValue::Date(a), StateValue::Date(b)) => {
return a == b;
}
(StateValue::Time(a), StateValue::Time(b)) => {
return a == b;
}
(StateValue::DateTime(a), StateValue::DateTime(b)) => {
return a == b;
}
(StateValue::DateTimeTZ(a), StateValue::DateTimeTZ(b)) => {
return a == b;
}
(StateValue::TimeTZ(a), StateValue::TimeTZ(b)) => {
return a == b;
}
(_, _) => return false,
}
}
}
impl PartialOrd for StateValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(a, b) if a.is_integer() && b.is_integer() => {
if let (Ok(ia), Ok(ib)) = (i64::try_from(a), i64::try_from(b)) {
return Some(ia.cmp(&ib));
};
return None;
}
(a, b) if a.is_float() && b.is_float() => {
if let (Ok(a), Ok(b)) = (f64::try_from(self), f64::try_from(other)) {
return a.partial_cmp(&b); // NaN respecte la sémantique IEEE (NaN != NaN)
}
return None;
}
(a, b) if a.is_string() && b.is_string() => {
let (a, b) = (self.to_string(), other.to_string());
return Some(a.cmp(&b)); // NaN respecte la sémantique IEEE (NaN != NaN)
}
(StateValue::Date(a), StateValue::Date(b)) => {
return Some(a.cmp(&b));
}
(StateValue::Time(a), StateValue::Time(b)) => {
return Some(a.cmp(&b));
}
(StateValue::DateTime(a), StateValue::DateTime(b)) => {
return Some(a.cmp(&b));
}
(StateValue::DateTimeTZ(a), StateValue::DateTimeTZ(b)) => {
return Some(a.cmp(&b));
}
(StateValue::TimeTZ(a), StateValue::TimeTZ(b)) => {
return Some(a.cmp(&b));
}
(_, _) => return None,
}
}
}

View File

@@ -0,0 +1,2 @@
pub trait UpnpValue {
}

View File

@@ -0,0 +1,33 @@
use std::convert::TryFrom;
use chrono::{DateTime,FixedOffset};
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for DateTime<FixedOffset> {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::DateTimeTZ(v) => Ok(v.clone()),
StateValue::TimeTZ(v) => Ok(v.clone()),
StateValue::String(v) => DateTime::parse_from_rfc3339(v)
.map_err(|e| StateValueError::ParseError(format!("Cannot parse DateTimeTZ from string '{}': {}", v, e))),
_ => Err(StateValueError::TypeError("Cannot cast to DateTime<FixedOffset>".into())),
}
}
}
impl TryFrom<StateValue> for DateTime<FixedOffset> {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
DateTime::<FixedOffset>::try_from(&value)
}
}
impl From<DateTime<FixedOffset>> for StateValue {
fn from(value: DateTime<FixedOffset>) -> Self {
StateValue::DateTimeTZ(value)
}
}

View File

@@ -0,0 +1,82 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for f32 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
const MAX_EXACT: i32 = 1 << f32::MANTISSA_DIGITS;
match value {
// --- Signed integers ---
StateValue::I1(v) => Ok(*v as f32),
StateValue::I2(v) => Ok(*v as f32),
StateValue::I4(v)
if *v > -MAX_EXACT &&
*v < MAX_EXACT => Ok(*v as f32),
StateValue::Int(v)
if *v >= -MAX_EXACT &&
*v <= MAX_EXACT as i32 => Ok(*v as f32),
// --- Unsigned integers ---
StateValue::UI1(v) => Ok(*v as f32),
StateValue::UI2(v) => Ok(*v as f32),
StateValue::UI4(v) if *v <= MAX_EXACT as u32 => Ok(*v as f32),
StateValue::UI4(_) => Err(StateValueError::TypeError(
"Cannot cast UI4 to f32: out of range".into(),
)),
// --- Floats ---
StateValue::R4(v) => Ok(*v), // déjà un f32
StateValue::R8(v)
if ! v.is_finite() ||
(*v <= f32::MAX as f64 &&
*v >= f32::MIN as f64) => Ok(*v as f32),
StateValue::R8(_) => Err(StateValueError::TypeError(
"Cannot cast R8 to f32: out of range".into(),
)),
StateValue::Number(v)
if ! v.is_finite() ||
(*v <= f32::MAX as f64 &&
*v >= f32::MIN as f64) => Ok(*v as f32),
StateValue::Number(_) => Err(StateValueError::TypeError(
"Cannot cast Number to f32: out of range".into(),
)),
StateValue::Fixed14_4(v)
if ! v.is_finite() ||
(*v <= f32::MAX as f64 &&
*v >= f32::MIN as f64) => Ok(*v as f32),
StateValue::Fixed14_4(_) => Err(StateValueError::TypeError(
"Cannot cast Fixed14_4 to f32: out of range".into(),
)),
StateValue::Boolean(v) => Ok((*v as i32) as Self),
StateValue::String(s) => s.parse::<f32>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as f32", s))
}),
// --- Par défaut : erreur ---
_ => Err(StateValueError::TypeError(
"Cannot cast to f32".into(),
)),
}
}
}
impl TryFrom<StateValue> for f32 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
f32::try_from(&value)
}
}
impl From<f32> for StateValue {
fn from(value: f32) -> Self {
StateValue::R4(value)
}
}

View File

@@ -0,0 +1,53 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for f64 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
// --- Signed integers ---
StateValue::I1(v) => Ok(*v as f64),
StateValue::I2(v) => Ok(*v as f64),
StateValue::I4(v) => Ok(*v as f64),
StateValue::Int(v) => Ok(*v as f64),
// --- Unsigned integers ---
StateValue::UI1(v) => Ok(*v as f64),
StateValue::UI2(v) => Ok(*v as f64),
StateValue::UI4(v) => Ok(*v as f64),
// --- Floats ---
StateValue::R4(v) => Ok(*v as f64),
StateValue::R8(v) => Ok(*v),
StateValue::Number(v) => Ok(*v),
StateValue::Fixed14_4(v) => Ok(*v),
StateValue::Boolean(v) => Ok((*v as i32) as Self),
StateValue::String(s) => s.parse::<f64>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as f64", s))
}),
// --- Par défaut : erreur ---
_ => Err(StateValueError::TypeError(
"Cannot cast to f64".into(),
)),
}
}
}
impl TryFrom<StateValue> for f64 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
f64::try_from(&value)
}
}
impl From<f64> for StateValue {
fn from(value: f64) -> Self {
StateValue::R8(value)
}
}

View File

@@ -0,0 +1,46 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
// Implémentations TryFrom<StateValue> pour types numériques
impl TryFrom<&StateValue> for i16 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::I1(v) => Ok(*v as i16),
StateValue::I2(v) => Ok(*v),
StateValue::I4(v) if *v <= i16::MAX as i32 && *v >= i16::MIN as i32 => Ok(*v as i16),
StateValue::Int(v) if *v <= i16::MAX as i32 && *v >= i16::MIN as i32 => Ok(*v as i16),
StateValue::UI1(v) => Ok(*v as i16),
StateValue::UI2(v) if *v <= i16::MAX as u16 => Ok(*v as i16),
StateValue::UI4(v) if *v <= i16::MAX as u32 => Ok(*v as i16),
StateValue::Boolean(v) => Ok(*v as Self),
StateValue::String(s) => s.parse::<i16>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as i16", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to i32".into())),
}
}
}
impl TryFrom<StateValue> for i16 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
i16::try_from(&value)
}
}
impl From<i16> for StateValue {
fn from(value: i16) -> Self {
StateValue::I2(value)
}
}

View File

@@ -0,0 +1,46 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for i32 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
// signés
StateValue::I1(v) => Ok(*v as i32),
StateValue::I2(v) => Ok(*v as i32),
StateValue::I4(v) => Ok(*v),
StateValue::Int(v) => Ok(*v),
// non signés
StateValue::UI1(v) => Ok(*v as i32),
StateValue::UI2(v) => Ok(*v as i32),
StateValue::UI4(v) if *v <= i32::MAX as u32 =>Ok(*v as i32),
StateValue::Boolean(v) => Ok(*v as Self),
StateValue::String(s) => s.parse::<i32>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as i32", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to i32".into())),
}
}
}
impl TryFrom<StateValue> for i32 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
i32::try_from(&value)
}
}
impl From<i32> for StateValue {
fn from(value: i32) -> Self {
StateValue::I4(value)
}
}

View File

@@ -0,0 +1,45 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for i64 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
// signés
StateValue::I1(v) => Ok(*v as i64),
StateValue::I2(v) => Ok(*v as i64),
StateValue::I4(v) => Ok(*v as i64),
StateValue::Int(v) => Ok(*v as i64),
// non signés
StateValue::UI1(v) => Ok(*v as i64),
StateValue::UI2(v) => Ok(*v as i64),
StateValue::UI4(v) => Ok(*v as i64), // toujours dans l'intervalle d'un i64
// booléen
StateValue::Boolean(v) => Ok(*v as i64),
// chaîne → i64
StateValue::String(s) => s.parse::<i64>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as i64", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to i64".into())),
}
}
}
impl TryFrom<StateValue> for i64 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
i64::try_from(&value)
}
}
impl From<i64> for StateValue {
fn from(value: i64) -> Self {
StateValue::Int(value as i32) // ⚠️ choix à discuter : Int est i32, pas i64
}
}

View File

@@ -0,0 +1,46 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
// Implémentations TryFrom<StateValue> pour types numériques
impl TryFrom<&StateValue> for i8 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::I1(v) if *v >= 0 => Ok(*v as i8),
StateValue::I2(v) if *v <= i8::MAX as i16 && *v >= i8::MIN as i16 => Ok(*v as i8),
StateValue::I4(v) if *v <= i8::MAX as i32 && *v >= i8::MIN as i32=> Ok(*v as i8),
StateValue::Int(v) if *v <= i8::MAX as i32 && *v >= i8::MIN as i32=> Ok(*v as i8),
StateValue::UI1(v) if *v <= i8::MAX as u8 => Ok(*v as i8),
StateValue::UI2(v) if *v <= i8::MAX as u16 => Ok(*v as i8),
StateValue::UI4(v) if *v <= i8::MAX as u32 => Ok(*v as i8),
StateValue::Boolean(v) => Ok(*v as Self),
StateValue::String(s) => s.parse::<i8>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as i8", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to i8".into())),
}
}
}
impl TryFrom<StateValue> for i8 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
i8::try_from(&value)
}
}
impl From<i8> for StateValue {
fn from(value: i8) -> Self {
StateValue::I1(value)
}
}

View File

@@ -0,0 +1,32 @@
use std::convert::TryFrom;
use chrono::NaiveDate;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for NaiveDate {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::Date(v) => Ok(v.clone()),
StateValue::String(v) => NaiveDate::parse_from_str(v, "%Y-%m-%d")
.map_err(|e| StateValueError::ParseError(format!("Cannot parse Date from string '{}': {}", v, e))),
_ => Err(StateValueError::TypeError("Cannot cast to NaiveDate".into())),
}
}
}
impl TryFrom<StateValue> for NaiveDate {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
NaiveDate::try_from(&value)
}
}
impl From<NaiveDate> for StateValue {
fn from(value: NaiveDate) -> Self {
StateValue::Date(value)
}
}

View File

@@ -0,0 +1,31 @@
use std::convert::TryFrom;
use chrono::NaiveDateTime;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for NaiveDateTime {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::DateTime(v) => Ok(v.clone()),
StateValue::String(v) => NaiveDateTime::parse_from_str(&v, "%Y-%m-%dT%H:%M:%S")
.map_err(|e| StateValueError::ParseError(format!("Cannot parse DateTime from string '{}': {}", v, e))),
_ => Err(StateValueError::TypeError("Cannot cast to NaiveDateTime".into())),
}
}
}
impl TryFrom<StateValue> for NaiveDateTime {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
NaiveDateTime::try_from(&value)
}
}
impl From<NaiveDateTime> for StateValue {
fn from(value: NaiveDateTime) -> Self {
StateValue::DateTime(value)
}
}

View File

@@ -0,0 +1,31 @@
use std::convert::TryFrom;
use chrono::NaiveTime;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for NaiveTime {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::Time(v) => Ok(v.clone()),
StateValue::String(v) => NaiveTime::parse_from_str(&v, "%H:%M:%S")
.map_err(|e| StateValueError::ParseError(format!("Cannot parse Time from string '{}': {}", v, e))),
_ => Err(StateValueError::TypeError("Cannot cast to NaiveTime".into())),
}
}
}
impl TryFrom<StateValue> for NaiveTime {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
NaiveTime::try_from(&value)
}
}
impl From<NaiveTime> for StateValue {
fn from(value: NaiveTime) -> Self {
StateValue::Time(value)
}
}

View File

@@ -0,0 +1,37 @@
use crate::variable_types::{StateValue, StateVarType};
impl From<&StateValue> for StateVarType {
fn from(value: &StateValue) -> Self {
match value {
StateValue::UI1(_) => StateVarType::UI1,
StateValue::UI2(_) => StateVarType::UI2,
StateValue::UI4(_) => StateVarType::UI4,
StateValue::I1(_) => StateVarType::I1,
StateValue::I2(_) => StateVarType::I2,
StateValue::I4(_) => StateVarType::I4,
StateValue::Int(_) => StateVarType::Int,
StateValue::R4(_) => StateVarType::R4,
StateValue::R8(_) => StateVarType::R8,
StateValue::Number(_) => StateVarType::Number,
StateValue::Fixed14_4(_) => StateVarType::Fixed14_4,
StateValue::Char(_) => StateVarType::Char,
StateValue::String(_) => StateVarType::String,
StateValue::BinBase64(_) => StateVarType::BinBase64,
StateValue::BinHex(_) => StateVarType::BinHex,
StateValue::URI(_) => StateVarType::URI,
StateValue::UUID(_) => StateVarType::UUID,
StateValue::Date(_) => StateVarType::Date,
StateValue::DateTime(_) => StateVarType::DateTime,
StateValue::DateTimeTZ(_) => StateVarType::DateTimeTZ,
StateValue::Time(_) => StateVarType::Time,
StateValue::TimeTZ(_) => StateVarType::TimeTZ,
StateValue::Boolean(_) => StateVarType::Boolean,
}
}
}
impl From<StateValue> for StateVarType {
fn from(value: StateValue) -> Self {
StateVarType::from(&value)
}
}

View File

@@ -0,0 +1,47 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
// Implémentations TryFrom<StateValue> pour types numériques
impl TryFrom<&StateValue> for u16 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::UI1(v) => Ok(*v as Self),
StateValue::UI2(v) => Ok(*v),
StateValue::UI4(v) if *v <= i16::MAX as u32 => Ok(*v as Self),
StateValue::I1(v) if *v >= 0 => Ok(*v as Self),
StateValue::I2(v) if *v >= 0 => Ok(*v as Self),
StateValue::I4(v) if *v >= 0 && *v <= u16::MAX as i32 => Ok(*v as Self),
StateValue::Int(v) if *v >= 0 && *v <= u16::MAX as i32 => Ok(*v as Self),
StateValue::Boolean(v) => Ok(*v as Self),
StateValue::String(s) => s.parse::<u16>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as u16", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to u16".into())),
}
}
}
impl TryFrom<StateValue> for u16 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
u16::try_from(&value)
}
}
impl From<u16> for StateValue {
fn from(value: u16) -> Self {
StateValue::UI2(value)
}
}

View File

@@ -0,0 +1,45 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<&StateValue> for u32 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::UI1(v) => Ok(*v as Self),
StateValue::UI2(v) => Ok(*v as Self),
StateValue::UI4(v) => Ok(*v),
StateValue::I1(v) if *v >= 0 => Ok(*v as Self),
StateValue::I2(v) if *v >= 0 => Ok(*v as Self),
StateValue::I4(v) if *v >= 0 => Ok(*v as Self),
StateValue::Int(v) if *v >= 0 => Ok(*v as Self),
StateValue::Boolean(v) => Ok(*v as Self),
StateValue::String(s) => s.parse::<u32>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as u32", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to u32".into())),
}
}
}
impl TryFrom<StateValue> for u32 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
u32::try_from(&value)
}
}
impl From<u32> for StateValue {
fn from(value: u32) -> Self {
StateValue::UI4(value)
}
}

View File

@@ -0,0 +1,45 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
// Implémentations TryFrom<StateValue> pour types numériques
impl TryFrom<&StateValue> for u8 {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
StateValue::UI1(v) => Ok(*v),
StateValue::UI2(v) if *v <= u8::MAX as u16 => Ok(*v as u8),
StateValue::UI4(v) if *v <= i8::MAX as u32 => Ok(*v as u8),
StateValue::I1(v) if *v >= 0 => Ok(*v as u8),
StateValue::I2(v) if *v >= 0 && *v <= u8::MAX as i16 => Ok(*v as u8),
StateValue::I4(v) if *v >= 0 && *v <= u8::MAX as i32 => Ok(*v as u8),
StateValue::Int(v) if *v >= 0 && *v <= u8::MAX as i32 => Ok(*v as u8),
StateValue::Boolean(v) => Ok(*v as Self),
StateValue::String(s) => s.parse::<u8>().map_err(|_| {
StateValueError::TypeError(format!("Cannot parse '{}' as u8", s))
}),
_ => Err(StateValueError::TypeError("Cannot cast to u8".into())),
}
}
}
impl TryFrom<StateValue> for u8 {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
u8::try_from(&value)
}
}
impl From<u8> for StateValue {
fn from(value: u8) -> Self {
StateValue::UI1(value)
}
}

View File

@@ -0,0 +1,31 @@
use std::convert::TryFrom;
use url::Url;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<StateValue> for Url {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
match value {
// Si déjà un URI encodé comme StateValue::URI
StateValue::URI(v) => Ok(v),
// Si c'est une String, on tente un parse
StateValue::String(v) => {
Url::parse(&v)
.map_err(|_| StateValueError::TypeError("Invalid URI string".into()))
}
// Autres types : erreur
_ => Err(StateValueError::TypeError("Cannot cast to Url".into())),
}
}
}
impl From<Url> for StateValue {
fn from(value: Url) -> Self {
StateValue::URI(value)
}
}

View File

@@ -0,0 +1,31 @@
use std::convert::TryFrom;
use uuid::Uuid;
use crate::variable_types::{StateValue, StateValueError};
impl TryFrom<StateValue> for Uuid {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
match value {
// Si déjà un URI encodé comme StateValue::URI
StateValue::UUID(v) => Ok(v),
// Si c'est une String, on tente un parse
StateValue::String(v) => {
Uuid::parse_str(&v)
.map_err(|_| StateValueError::TypeError("Invalid UUID string".into()))
}
// Autres types : erreur
_ => Err(StateValueError::TypeError("Cannot cast to Uuid".into())),
}
}
}
impl From<Uuid> for StateValue {
fn from(value: Uuid) -> Self {
StateValue::UUID(value)
}
}

View File

@@ -0,0 +1,45 @@
use std::convert::TryFrom;
use crate::variable_types::{StateValue, StateValueError};
use base64::{engine::general_purpose::STANDARD, Engine as _};
impl TryFrom<&StateValue> for Vec<u8> {
type Error = StateValueError;
fn try_from(value: &StateValue) -> Result<Self, Self::Error> {
match value {
// Déjà un vecteur binaire
StateValue::BinBase64(v) => STANDARD.decode(v).map_err(
|e| StateValueError::ParseError(format!("Base64 decode error: {}", e))),
StateValue::BinHex(v) => hex::decode(v).map_err(
|e| StateValueError::ParseError(format!("BinHex decode error: {}", e))),
// Conversion depuis une chaîne encodée
StateValue::String(s) => {
// Essayer Base64
if let Ok(bytes) = STANDARD.decode(s) {
return Ok(bytes);
}
// Essayer Hex
if let Ok(bytes) = hex::decode(s) {
return Ok(bytes);
}
Err(StateValueError::ParseError(format!(
"Cannot parse string '{}' as binary",
s
)))
}
_ => Err(StateValueError::TypeError(
"Cannot cast to binary Vec<u8>".into(),
)),
}
}
}
impl TryFrom<StateValue> for Vec<u8> {
type Error = StateValueError;
fn try_from(value: StateValue) -> Result<Self, Self::Error> {
Vec::<u8>::try_from(&value)
}
}

2
pmoupnp/webapp/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
dist
node_modules

1
pmoupnp/webapp/node_modules/.bin/esbuild generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../esbuild/bin/esbuild

1
pmoupnp/webapp/node_modules/.bin/marked generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../marked/bin/marked.js

1
pmoupnp/webapp/node_modules/.bin/nanoid generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../nanoid/bin/nanoid.cjs

1
pmoupnp/webapp/node_modules/.bin/parser generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../@babel/parser/bin/babel-parser.js

1
pmoupnp/webapp/node_modules/.bin/rollup generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../rollup/dist/bin/rollup

1
pmoupnp/webapp/node_modules/.bin/tsc generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../typescript/bin/tsc

1
pmoupnp/webapp/node_modules/.bin/tsserver generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../typescript/bin/tsserver

1
pmoupnp/webapp/node_modules/.bin/vite generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../vite/bin/vite.js

1
pmoupnp/webapp/node_modules/.bin/vue-tsc generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../vue-tsc/bin/vue-tsc.js

1514
pmoupnp/webapp/node_modules/.package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{"root":["../../src/main.ts","../../src/shims-vue.d.ts","../../src/router/index.ts","../../src/app.vue","../../src/components/helloworld.vue","../../src/components/logview.vue"],"version":"5.8.3"}

View File

@@ -0,0 +1 @@
{"root":["../../vite.config.ts"],"version":"5.8.3"}

15
pmoupnp/webapp/node_modules/.vite/deps/_metadata.json generated vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"hash": "55ffb9fd",
"configHash": "38b44685",
"lockfileHash": "67a231c1",
"browserHash": "0b84b257",
"optimized": {
"vue": {
"src": "../../vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "6eecd6fc",
"needsInterop": false
}
},
"chunks": {}
}

3
pmoupnp/webapp/node_modules/.vite/deps/package.json generated vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"type": "module"
}

12704
pmoupnp/webapp/node_modules/.vite/deps/vue.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

7
pmoupnp/webapp/node_modules/.vite/deps/vue.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,137 @@
// @ts-nocheck
export {};
; declare global {
const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
const __VLS_unref: typeof import('vue').unref;
const __VLS_placeholder: any;
type __VLS_NativeElements = __VLS_SpreadMerge<SVGElementTagNameMap, HTMLElementTagNameMap>;
type __VLS_IntrinsicElements = import('vue/jsx-runtime').JSX.IntrinsicElements;
type __VLS_Element = import('vue/jsx-runtime').JSX.Element;
type __VLS_GlobalComponents = import('vue').GlobalComponents;
type __VLS_GlobalDirectives = import('vue').GlobalDirectives;
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_SpreadMerge<A, B> = Omit<A, keyof B> & B;
type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? { [K in N0]: LocalComponents[N2] } :
N3 extends keyof LocalComponents ? { [K in N0]: LocalComponents[N3] } :
Self extends object ? { [K in N0]: Self } :
N1 extends keyof __VLS_GlobalComponents ? { [K in N0]: __VLS_GlobalComponents[N1] } :
N2 extends keyof __VLS_GlobalComponents ? { [K in N0]: __VLS_GlobalComponents[N2] } :
N3 extends keyof __VLS_GlobalComponents ? { [K in N0]: __VLS_GlobalComponents[N3] } :
{};
type __VLS_FunctionalComponentCtx<T, K> = __VLS_PickNotAny<'__ctx' extends keyof __VLS_PickNotAny<K, {}>
? K extends { __ctx?: infer Ctx } ? NonNullable<Ctx> : never : any
, T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
>;
type __VLS_FunctionalComponentProps<T, K> = '__ctx' extends keyof __VLS_PickNotAny<K, {}>
? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
: T extends (props: infer P, ...args: any) => any ? P
: {};
type __VLS_FunctionalComponent<T> = (props: (T extends { $props: infer Props } ? Props : {}) & Record<string, unknown>, ctx?: any) => __VLS_Element & {
__ctx?: {
attrs?: any;
slots?: T extends { $slots: infer Slots } ? Slots : Record<string, any>;
emit?: T extends { $emit: infer Emit } ? Emit : {};
props?: (T extends { $props: infer Props } ? Props : {}) & Record<string, unknown>;
expose?: (exposed: T) => void;
};
};
type __VLS_IsFunction<T, K> = K extends keyof T
? __VLS_IsAny<T[K]> extends false
? unknown extends T[K]
? false
: true
: false
: false;
type __VLS_NormalizeComponentEvent<
Props,
Emits,
onEvent extends keyof Props,
Event extends keyof Emits,
CamelizedEvent extends keyof Emits,
> = __VLS_IsFunction<Props, onEvent> extends true
? Props
: __VLS_IsFunction<Emits, Event> extends true
? { [K in onEvent]?: Emits[Event] }
: __VLS_IsFunction<Emits, CamelizedEvent> extends true
? { [K in onEvent]?: Emits[CamelizedEvent] }
: Props;
// fix https://github.com/vuejs/language-tools/issues/926
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
? U extends T
? never
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
: never;
type __VLS_OverloadUnion<T> = Exclude<
__VLS_OverloadUnionInner<(() => never) & T>,
T extends () => never ? never : () => never
>;
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
? F extends (event: infer E, ...args: infer A) => any
? { [K in E & string]: (...args: A) => void; }
: never
: never;
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
__VLS_UnionToIntersection<
__VLS_ConstructorOverloads<T> & {
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
}
>
>;
type __VLS_EmitsToProps<T> = __VLS_PrettifyGlobal<{
[K in string & keyof T as `on${Capitalize<K>}`]?:
(...args: T[K] extends (...args: infer P) => any ? P : T[K] extends null ? any[] : never) => any;
}>;
type __VLS_ResolveEmits<
Comp,
Emits,
TypeEmits = {},
NormalizedEmits = __VLS_NormalizeEmits<Emits> extends infer E ? string extends keyof E ? {} : E : never,
> = __VLS_SpreadMerge<NormalizedEmits, TypeEmits>;
type __VLS_ResolveDirectives<T> = {
[K in keyof T & string as `v${Capitalize<K>}`]: T[K];
};
type __VLS_PrettifyGlobal<T> = { [K in keyof T as K]: T[K]; } & {};
type __VLS_WithDefaultsGlobal<P, D> = {
[K in keyof P as K extends keyof D ? K : never]-?: P[K];
} & {
[K in keyof P as K extends keyof D ? never : K]: P[K];
};
type __VLS_UseTemplateRef<T> = Readonly<import('vue').ShallowRef<T | null>>;
type __VLS_ProxyRefs<T> = import('vue').ShallowUnwrapRef<T>;
function __VLS_getVForSourceType<T extends number | string | any[] | Iterable<any>>(source: T): [
item: T extends number ? number
: T extends string ? string
: T extends any[] ? T[number]
: T extends Iterable<infer T1> ? T1
: any,
index: number,
][];
function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
function __VLS_getSlotParameters<S, D extends S>(slot: S, decl?: D):
D extends (...args: infer P) => any ? P : any[];
function __VLS_asFunctionalDirective<T>(dir: T): T extends import('vue').ObjectDirective
? NonNullable<T['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>
: T extends (...args: any) => any
? T
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any ? __VLS_FunctionalComponent<K>
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: __VLS_FunctionalComponent<{}>;
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (attrs: T & Record<string, unknown>) => void;
function __VLS_asFunctionalSlot<S>(slot: S): S extends () => infer R ? (props: {}) => R : NonNullable<S>;
function __VLS_tryAsConstant<const T>(t: T): T;
}

View File

@@ -0,0 +1,137 @@
// @ts-nocheck
export {};
; declare global {
const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
const __VLS_unref: typeof import('vue').unref;
const __VLS_placeholder: any;
type __VLS_NativeElements = __VLS_SpreadMerge<SVGElementTagNameMap, HTMLElementTagNameMap>;
type __VLS_IntrinsicElements = import('vue/jsx-runtime').JSX.IntrinsicElements;
type __VLS_Element = import('vue/jsx-runtime').JSX.Element;
type __VLS_GlobalComponents = import('vue').GlobalComponents;
type __VLS_GlobalDirectives = import('vue').GlobalDirectives;
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_SpreadMerge<A, B> = Omit<A, keyof B> & B;
type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? { [K in N0]: LocalComponents[N2] } :
N3 extends keyof LocalComponents ? { [K in N0]: LocalComponents[N3] } :
Self extends object ? { [K in N0]: Self } :
N1 extends keyof __VLS_GlobalComponents ? { [K in N0]: __VLS_GlobalComponents[N1] } :
N2 extends keyof __VLS_GlobalComponents ? { [K in N0]: __VLS_GlobalComponents[N2] } :
N3 extends keyof __VLS_GlobalComponents ? { [K in N0]: __VLS_GlobalComponents[N3] } :
{};
type __VLS_FunctionalComponentCtx<T, K> = __VLS_PickNotAny<'__ctx' extends keyof __VLS_PickNotAny<K, {}>
? K extends { __ctx?: infer Ctx } ? NonNullable<Ctx> : never : any
, T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
>;
type __VLS_FunctionalComponentProps<T, K> = '__ctx' extends keyof __VLS_PickNotAny<K, {}>
? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
: T extends (props: infer P, ...args: any) => any ? P
: {};
type __VLS_FunctionalComponent<T> = (props: (T extends { $props: infer Props } ? Props : {}) & Record<string, unknown>, ctx?: any) => __VLS_Element & {
__ctx?: {
attrs?: any;
slots?: T extends { $slots: infer Slots } ? Slots : Record<string, any>;
emit?: T extends { $emit: infer Emit } ? Emit : {};
props?: (T extends { $props: infer Props } ? Props : {}) & Record<string, unknown>;
expose?: (exposed: T) => void;
};
};
type __VLS_IsFunction<T, K> = K extends keyof T
? __VLS_IsAny<T[K]> extends false
? unknown extends T[K]
? false
: true
: false
: false;
type __VLS_NormalizeComponentEvent<
Props,
Emits,
onEvent extends keyof Props,
Event extends keyof Emits,
CamelizedEvent extends keyof Emits,
> = __VLS_IsFunction<Props, onEvent> extends true
? Props
: __VLS_IsFunction<Emits, Event> extends true
? { [K in onEvent]?: Emits[Event] }
: __VLS_IsFunction<Emits, CamelizedEvent> extends true
? { [K in onEvent]?: Emits[CamelizedEvent] }
: Props;
// fix https://github.com/vuejs/language-tools/issues/926
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
? U extends T
? never
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
: never;
type __VLS_OverloadUnion<T> = Exclude<
__VLS_OverloadUnionInner<(() => never) & T>,
T extends () => never ? never : () => never
>;
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
? F extends (event: infer E, ...args: infer A) => any
? { [K in E & string]: (...args: A) => void; }
: never
: never;
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
__VLS_UnionToIntersection<
__VLS_ConstructorOverloads<T> & {
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
}
>
>;
type __VLS_EmitsToProps<T> = __VLS_PrettifyGlobal<{
[K in string & keyof T as `on${Capitalize<K>}`]?:
(...args: T[K] extends (...args: infer P) => any ? P : T[K] extends null ? any[] : never) => any;
}>;
type __VLS_ResolveEmits<
Comp,
Emits,
TypeEmits = Comp extends { __typeEmits?: infer T } ? unknown extends T ? {} : import('vue').ShortEmitsToObject<T> : {},
NormalizedEmits = __VLS_NormalizeEmits<Emits> extends infer E ? string extends keyof E ? {} : E : never,
> = __VLS_SpreadMerge<NormalizedEmits, TypeEmits>;
type __VLS_ResolveDirectives<T> = {
[K in keyof T & string as `v${Capitalize<K>}`]: T[K];
};
type __VLS_PrettifyGlobal<T> = { [K in keyof T as K]: T[K]; } & {};
type __VLS_WithDefaultsGlobal<P, D> = {
[K in keyof P as K extends keyof D ? K : never]-?: P[K];
} & {
[K in keyof P as K extends keyof D ? never : K]: P[K];
};
type __VLS_UseTemplateRef<T> = Readonly<import('vue').ShallowRef<T | null>>;
type __VLS_ProxyRefs<T> = import('vue').ShallowUnwrapRef<T>;
function __VLS_getVForSourceType<T extends number | string | any[] | Iterable<any>>(source: T): [
item: T extends number ? number
: T extends string ? string
: T extends any[] ? T[number]
: T extends Iterable<infer T1> ? T1
: any,
index: number,
][];
function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
function __VLS_getSlotParameters<S, D extends S>(slot: S, decl?: D):
D extends (...args: infer P) => any ? P : any[];
function __VLS_asFunctionalDirective<T>(dir: T): T extends import('vue').ObjectDirective
? NonNullable<T['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>
: T extends (...args: any) => any
? T
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any ? __VLS_FunctionalComponent<K>
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: __VLS_FunctionalComponent<{}>;
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (attrs: T & Record<string, unknown>) => void;
function __VLS_asFunctionalSlot<S>(slot: S): S extends () => infer R ? (props: {}) => R : NonNullable<S>;
function __VLS_tryAsConstant<const T>(t: T): T;
}

View File

@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
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.

View File

@@ -0,0 +1,19 @@
# @babel/helper-string-parser
> A utility package to parse strings
See our website [@babel/helper-string-parser](https://babeljs.io/docs/babel-helper-string-parser) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-string-parser
```
or using yarn:
```sh
yarn add @babel/helper-string-parser
```

View File

@@ -0,0 +1,295 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.readCodePoint = readCodePoint;
exports.readInt = readInt;
exports.readStringContents = readStringContents;
var _isDigit = function isDigit(code) {
return code >= 48 && code <= 57;
};
const forbiddenNumericSeparatorSiblings = {
decBinOct: new Set([46, 66, 69, 79, 95, 98, 101, 111]),
hex: new Set([46, 88, 95, 120])
};
const isAllowedNumericSeparatorSibling = {
bin: ch => ch === 48 || ch === 49,
oct: ch => ch >= 48 && ch <= 55,
dec: ch => ch >= 48 && ch <= 57,
hex: ch => ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102
};
function readStringContents(type, input, pos, lineStart, curLine, errors) {
const initialPos = pos;
const initialLineStart = lineStart;
const initialCurLine = curLine;
let out = "";
let firstInvalidLoc = null;
let chunkStart = pos;
const {
length
} = input;
for (;;) {
if (pos >= length) {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
out += input.slice(chunkStart, pos);
break;
}
const ch = input.charCodeAt(pos);
if (isStringEnd(type, ch, input, pos)) {
out += input.slice(chunkStart, pos);
break;
}
if (ch === 92) {
out += input.slice(chunkStart, pos);
const res = readEscapedChar(input, pos, lineStart, curLine, type === "template", errors);
if (res.ch === null && !firstInvalidLoc) {
firstInvalidLoc = {
pos,
lineStart,
curLine
};
} else {
out += res.ch;
}
({
pos,
lineStart,
curLine
} = res);
chunkStart = pos;
} else if (ch === 8232 || ch === 8233) {
++pos;
++curLine;
lineStart = pos;
} else if (ch === 10 || ch === 13) {
if (type === "template") {
out += input.slice(chunkStart, pos) + "\n";
++pos;
if (ch === 13 && input.charCodeAt(pos) === 10) {
++pos;
}
++curLine;
chunkStart = lineStart = pos;
} else {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
}
} else {
++pos;
}
}
return {
pos,
str: out,
firstInvalidLoc,
lineStart,
curLine,
containsInvalid: !!firstInvalidLoc
};
}
function isStringEnd(type, ch, input, pos) {
if (type === "template") {
return ch === 96 || ch === 36 && input.charCodeAt(pos + 1) === 123;
}
return ch === (type === "double" ? 34 : 39);
}
function readEscapedChar(input, pos, lineStart, curLine, inTemplate, errors) {
const throwOnInvalid = !inTemplate;
pos++;
const res = ch => ({
pos,
ch,
lineStart,
curLine
});
const ch = input.charCodeAt(pos++);
switch (ch) {
case 110:
return res("\n");
case 114:
return res("\r");
case 120:
{
let code;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 2, false, throwOnInvalid, errors));
return res(code === null ? null : String.fromCharCode(code));
}
case 117:
{
let code;
({
code,
pos
} = readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors));
return res(code === null ? null : String.fromCodePoint(code));
}
case 116:
return res("\t");
case 98:
return res("\b");
case 118:
return res("\u000b");
case 102:
return res("\f");
case 13:
if (input.charCodeAt(pos) === 10) {
++pos;
}
case 10:
lineStart = pos;
++curLine;
case 8232:
case 8233:
return res("");
case 56:
case 57:
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(pos - 1, lineStart, curLine);
}
default:
if (ch >= 48 && ch <= 55) {
const startPos = pos - 1;
const match = /^[0-7]+/.exec(input.slice(startPos, pos + 2));
let octalStr = match[0];
let octal = parseInt(octalStr, 8);
if (octal > 255) {
octalStr = octalStr.slice(0, -1);
octal = parseInt(octalStr, 8);
}
pos += octalStr.length - 1;
const next = input.charCodeAt(pos);
if (octalStr !== "0" || next === 56 || next === 57) {
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(startPos, lineStart, curLine);
}
}
return res(String.fromCharCode(octal));
}
return res(String.fromCharCode(ch));
}
}
function readHexChar(input, pos, lineStart, curLine, len, forceLen, throwOnInvalid, errors) {
const initialPos = pos;
let n;
({
n,
pos
} = readInt(input, pos, lineStart, curLine, 16, len, forceLen, false, errors, !throwOnInvalid));
if (n === null) {
if (throwOnInvalid) {
errors.invalidEscapeSequence(initialPos, lineStart, curLine);
} else {
pos = initialPos - 1;
}
}
return {
code: n,
pos
};
}
function readInt(input, pos, lineStart, curLine, radix, len, forceLen, allowNumSeparator, errors, bailOnError) {
const start = pos;
const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
const isAllowedSibling = radix === 16 ? isAllowedNumericSeparatorSibling.hex : radix === 10 ? isAllowedNumericSeparatorSibling.dec : radix === 8 ? isAllowedNumericSeparatorSibling.oct : isAllowedNumericSeparatorSibling.bin;
let invalid = false;
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = input.charCodeAt(pos);
let val;
if (code === 95 && allowNumSeparator !== "bail") {
const prev = input.charCodeAt(pos - 1);
const next = input.charCodeAt(pos + 1);
if (!allowNumSeparator) {
if (bailOnError) return {
n: null,
pos
};
errors.numericSeparatorInEscapeSequence(pos, lineStart, curLine);
} else if (Number.isNaN(next) || !isAllowedSibling(next) || forbiddenSiblings.has(prev) || forbiddenSiblings.has(next)) {
if (bailOnError) return {
n: null,
pos
};
errors.unexpectedNumericSeparator(pos, lineStart, curLine);
}
++pos;
continue;
}
if (code >= 97) {
val = code - 97 + 10;
} else if (code >= 65) {
val = code - 65 + 10;
} else if (_isDigit(code)) {
val = code - 48;
} else {
val = Infinity;
}
if (val >= radix) {
if (val <= 9 && bailOnError) {
return {
n: null,
pos
};
} else if (val <= 9 && errors.invalidDigit(pos, lineStart, curLine, radix)) {
val = 0;
} else if (forceLen) {
val = 0;
invalid = true;
} else {
break;
}
}
++pos;
total = total * radix + val;
}
if (pos === start || len != null && pos - start !== len || invalid) {
return {
n: null,
pos
};
}
return {
n: total,
pos
};
}
function readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors) {
const ch = input.charCodeAt(pos);
let code;
if (ch === 123) {
++pos;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, input.indexOf("}", pos) - pos, true, throwOnInvalid, errors));
++pos;
if (code !== null && code > 0x10ffff) {
if (throwOnInvalid) {
errors.invalidCodePoint(pos, lineStart, curLine);
} else {
return {
code: null,
pos
};
}
}
} else {
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 4, false, throwOnInvalid, errors));
}
return {
code,
pos
};
}
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,31 @@
{
"name": "@babel/helper-string-parser",
"version": "7.27.1",
"description": "A utility package to parse strings",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-string-parser"
},
"homepage": "https://babel.dev/docs/en/next/babel-helper-string-parser",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"devDependencies": {
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"type": "commonjs"
}

View File

@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
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.

View File

@@ -0,0 +1,19 @@
# @babel/helper-validator-identifier
> Validate identifier/keywords name
See our website [@babel/helper-validator-identifier](https://babeljs.io/docs/babel-helper-validator-identifier) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-validator-identifier
```
or using yarn:
```sh
yarn add @babel/helper-validator-identifier
```

View File

@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isIdentifierChar = isIdentifierChar;
exports.isIdentifierName = isIdentifierName;
exports.isIdentifierStart = isIdentifierStart;
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7cd\ua7d0\ua7d1\ua7d3\ua7d5-\ua7dc\ua7f2-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
let nonASCIIidentifierChars = "\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65";
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 2, 60, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 328, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 129, 74, 6, 0, 67, 12, 65, 1, 2, 0, 29, 6135, 9, 1237, 42, 9, 8936, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 496, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4153, 7, 221, 3, 5761, 15, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 4191];
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 80, 3, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 343, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 330, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 726, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
function isInAstralSet(code, set) {
let pos = 0x10000;
for (let i = 0, length = set.length; i < length; i += 2) {
pos += set[i];
if (pos > code) return false;
pos += set[i + 1];
if (pos >= code) return true;
}
return false;
}
function isIdentifierStart(code) {
if (code < 65) return code === 36;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes);
}
function isIdentifierChar(code) {
if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
function isIdentifierName(name) {
let isFirst = true;
for (let i = 0; i < name.length; i++) {
let cp = name.charCodeAt(i);
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
const trail = name.charCodeAt(++i);
if ((trail & 0xfc00) === 0xdc00) {
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
}
}
if (isFirst) {
isFirst = false;
if (!isIdentifierStart(cp)) {
return false;
}
} else if (!isIdentifierChar(cp)) {
return false;
}
}
return !isFirst;
}
//# sourceMappingURL=identifier.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "isIdentifierChar", {
enumerable: true,
get: function () {
return _identifier.isIdentifierChar;
}
});
Object.defineProperty(exports, "isIdentifierName", {
enumerable: true,
get: function () {
return _identifier.isIdentifierName;
}
});
Object.defineProperty(exports, "isIdentifierStart", {
enumerable: true,
get: function () {
return _identifier.isIdentifierStart;
}
});
Object.defineProperty(exports, "isKeyword", {
enumerable: true,
get: function () {
return _keyword.isKeyword;
}
});
Object.defineProperty(exports, "isReservedWord", {
enumerable: true,
get: function () {
return _keyword.isReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindOnlyReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindReservedWord;
}
});
Object.defineProperty(exports, "isStrictReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictReservedWord;
}
});
var _identifier = require("./identifier.js");
var _keyword = require("./keyword.js");
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_identifier","require","_keyword"],"sources":["../src/index.ts"],"sourcesContent":["export {\n isIdentifierName,\n isIdentifierChar,\n isIdentifierStart,\n} from \"./identifier.ts\";\nexport {\n isReservedWord,\n isStrictBindOnlyReservedWord,\n isStrictBindReservedWord,\n isStrictReservedWord,\n isKeyword,\n} from \"./keyword.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA","ignoreList":[]}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isKeyword = isKeyword;
exports.isReservedWord = isReservedWord;
exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
exports.isStrictBindReservedWord = isStrictBindReservedWord;
exports.isStrictReservedWord = isStrictReservedWord;
const reservedWords = {
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
strictBind: ["eval", "arguments"]
};
const keywords = new Set(reservedWords.keyword);
const reservedWordsStrictSet = new Set(reservedWords.strict);
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
function isReservedWord(word, inModule) {
return inModule && word === "await" || word === "enum";
}
function isStrictReservedWord(word, inModule) {
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
}
function isStrictBindOnlyReservedWord(word) {
return reservedWordsStrictBindSet.has(word);
}
function isStrictBindReservedWord(word, inModule) {
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
}
function isKeyword(word) {
return keywords.has(word);
}
//# sourceMappingURL=keyword.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["reservedWords","keyword","strict","strictBind","keywords","Set","reservedWordsStrictSet","reservedWordsStrictBindSet","isReservedWord","word","inModule","isStrictReservedWord","has","isStrictBindOnlyReservedWord","isStrictBindReservedWord","isKeyword"],"sources":["../src/keyword.ts"],"sourcesContent":["const reservedWords = {\n keyword: [\n \"break\",\n \"case\",\n \"catch\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"do\",\n \"else\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"return\",\n \"switch\",\n \"throw\",\n \"try\",\n \"var\",\n \"const\",\n \"while\",\n \"with\",\n \"new\",\n \"this\",\n \"super\",\n \"class\",\n \"extends\",\n \"export\",\n \"import\",\n \"null\",\n \"true\",\n \"false\",\n \"in\",\n \"instanceof\",\n \"typeof\",\n \"void\",\n \"delete\",\n ],\n strict: [\n \"implements\",\n \"interface\",\n \"let\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n \"yield\",\n ],\n strictBind: [\"eval\", \"arguments\"],\n};\nconst keywords = new Set(reservedWords.keyword);\nconst reservedWordsStrictSet = new Set(reservedWords.strict);\nconst reservedWordsStrictBindSet = new Set(reservedWords.strictBind);\n\n/**\n * Checks if word is a reserved word in non-strict mode\n */\nexport function isReservedWord(word: string, inModule: boolean): boolean {\n return (inModule && word === \"await\") || word === \"enum\";\n}\n\n/**\n * Checks if word is a reserved word in non-binding strict mode\n *\n * Includes non-strict reserved words\n */\nexport function isStrictReservedWord(word: string, inModule: boolean): boolean {\n return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode, but it is allowed as\n * a normal identifier.\n */\nexport function isStrictBindOnlyReservedWord(word: string): boolean {\n return reservedWordsStrictBindSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode\n *\n * Includes non-strict reserved words and non-binding strict reserved words\n */\nexport function isStrictBindReservedWord(\n word: string,\n inModule: boolean,\n): boolean {\n return (\n isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word)\n );\n}\n\nexport function isKeyword(word: string): boolean {\n return keywords.has(word);\n}\n"],"mappings":";;;;;;;;;;AAAA,MAAMA,aAAa,GAAG;EACpBC,OAAO,EAAE,CACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACT,IAAI,EACJ,MAAM,EACN,SAAS,EACT,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,QAAQ,CACT;EACDC,MAAM,EAAE,CACN,YAAY,EACZ,WAAW,EACX,KAAK,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,CACR;EACDC,UAAU,EAAE,CAAC,MAAM,EAAE,WAAW;AAClC,CAAC;AACD,MAAMC,QAAQ,GAAG,IAAIC,GAAG,CAACL,aAAa,CAACC,OAAO,CAAC;AAC/C,MAAMK,sBAAsB,GAAG,IAAID,GAAG,CAACL,aAAa,CAACE,MAAM,CAAC;AAC5D,MAAMK,0BAA0B,GAAG,IAAIF,GAAG,CAACL,aAAa,CAACG,UAAU,CAAC;AAK7D,SAASK,cAAcA,CAACC,IAAY,EAAEC,QAAiB,EAAW;EACvE,OAAQA,QAAQ,IAAID,IAAI,KAAK,OAAO,IAAKA,IAAI,KAAK,MAAM;AAC1D;AAOO,SAASE,oBAAoBA,CAACF,IAAY,EAAEC,QAAiB,EAAW;EAC7E,OAAOF,cAAc,CAACC,IAAI,EAAEC,QAAQ,CAAC,IAAIJ,sBAAsB,CAACM,GAAG,CAACH,IAAI,CAAC;AAC3E;AAMO,SAASI,4BAA4BA,CAACJ,IAAY,EAAW;EAClE,OAAOF,0BAA0B,CAACK,GAAG,CAACH,IAAI,CAAC;AAC7C;AAOO,SAASK,wBAAwBA,CACtCL,IAAY,EACZC,QAAiB,EACR;EACT,OACEC,oBAAoB,CAACF,IAAI,EAAEC,QAAQ,CAAC,IAAIG,4BAA4B,CAACJ,IAAI,CAAC;AAE9E;AAEO,SAASM,SAASA,CAACN,IAAY,EAAW;EAC/C,OAAOL,QAAQ,CAACQ,GAAG,CAACH,IAAI,CAAC;AAC3B","ignoreList":[]}

View File

@@ -0,0 +1,31 @@
{
"name": "@babel/helper-validator-identifier",
"version": "7.27.1",
"description": "Validate identifier/keywords name",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-validator-identifier"
},
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"devDependencies": {
"@unicode/unicode-16.0.0": "^1.0.0",
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"type": "commonjs"
}

1073
pmoupnp/webapp/node_modules/@babel/parser/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

19
pmoupnp/webapp/node_modules/@babel/parser/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
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.

19
pmoupnp/webapp/node_modules/@babel/parser/README.md generated vendored Normal file
View File

@@ -0,0 +1,19 @@
# @babel/parser
> A JavaScript parser
See our website [@babel/parser](https://babeljs.io/docs/babel-parser) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20parser%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/parser
```
or using yarn:
```sh
yarn add @babel/parser --dev
```

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env node
/* eslint-disable no-var, unicorn/prefer-node-protocol */
var parser = require("..");
var fs = require("fs");
var filename = process.argv[2];
if (!filename) {
console.error("no filename specified");
} else {
var file = fs.readFileSync(filename, "utf8");
var ast = parser.parse(file);
console.log(JSON.stringify(ast, null, " "));
}

14595
pmoupnp/webapp/node_modules/@babel/parser/lib/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

50
pmoupnp/webapp/node_modules/@babel/parser/package.json generated vendored Normal file
View File

@@ -0,0 +1,50 @@
{
"name": "@babel/parser",
"version": "7.28.4",
"description": "A JavaScript parser",
"author": "The Babel Team (https://babel.dev/team)",
"homepage": "https://babel.dev/docs/en/next/babel-parser",
"bugs": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A+parser+%28babylon%29%22+is%3Aopen",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"keywords": [
"babel",
"javascript",
"parser",
"tc39",
"ecmascript",
"@babel/parser"
],
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-parser"
},
"main": "./lib/index.js",
"types": "./typings/babel-parser.d.ts",
"files": [
"bin",
"lib",
"typings/babel-parser.d.ts",
"index.cjs"
],
"engines": {
"node": ">=6.0.0"
},
"# dependencies": "This package doesn't actually have runtime dependencies. @babel/types is only needed for type definitions.",
"dependencies": {
"@babel/types": "^7.28.4"
},
"devDependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/helper-check-duplicate-nodes": "^7.27.1",
"@babel/helper-fixtures": "^7.28.0",
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
"charcodes": "^0.2.0"
},
"bin": "./bin/babel-parser.js",
"type": "commonjs"
}

View File

@@ -0,0 +1,239 @@
// This file is auto-generated! Do not modify it directly.
// Run `yarn gulp bundle-dts` to re-generate it.
/* eslint-disable @typescript-eslint/consistent-type-imports, @typescript-eslint/no-redundant-type-constituents */
import { File, Expression } from '@babel/types';
type BABEL_8_BREAKING = false;
type IF_BABEL_7<V> = false extends BABEL_8_BREAKING ? V : never;
type Plugin$1 =
| "asyncDoExpressions"
| IF_BABEL_7<"asyncGenerators">
| IF_BABEL_7<"bigInt">
| IF_BABEL_7<"classPrivateMethods">
| IF_BABEL_7<"classPrivateProperties">
| IF_BABEL_7<"classProperties">
| IF_BABEL_7<"classStaticBlock">
| IF_BABEL_7<"decimal">
| "decorators-legacy"
| "deferredImportEvaluation"
| "decoratorAutoAccessors"
| "destructuringPrivate"
| "deprecatedImportAssert"
| "doExpressions"
| IF_BABEL_7<"dynamicImport">
| IF_BABEL_7<"explicitResourceManagement">
| "exportDefaultFrom"
| IF_BABEL_7<"exportNamespaceFrom">
| "flow"
| "flowComments"
| "functionBind"
| "functionSent"
| "importMeta"
| "jsx"
| IF_BABEL_7<"jsonStrings">
| IF_BABEL_7<"logicalAssignment">
| IF_BABEL_7<"importAssertions">
| IF_BABEL_7<"importReflection">
| "moduleBlocks"
| IF_BABEL_7<"moduleStringNames">
| IF_BABEL_7<"nullishCoalescingOperator">
| IF_BABEL_7<"numericSeparator">
| IF_BABEL_7<"objectRestSpread">
| IF_BABEL_7<"optionalCatchBinding">
| IF_BABEL_7<"optionalChaining">
| "partialApplication"
| "placeholders"
| IF_BABEL_7<"privateIn">
| IF_BABEL_7<"regexpUnicodeSets">
| "sourcePhaseImports"
| "throwExpressions"
| IF_BABEL_7<"topLevelAwait">
| "v8intrinsic"
| ParserPluginWithOptions[0];
type ParserPluginWithOptions =
| ["decorators", DecoratorsPluginOptions]
| ["discardBinding", { syntaxType: "void" }]
| ["estree", { classFeatures?: boolean }]
| IF_BABEL_7<["importAttributes", { deprecatedAssertSyntax: boolean }]>
| IF_BABEL_7<["moduleAttributes", { version: "may-2020" }]>
| ["optionalChainingAssign", { version: "2023-07" }]
| ["pipelineOperator", PipelineOperatorPluginOptions]
| ["recordAndTuple", RecordAndTuplePluginOptions]
| ["flow", FlowPluginOptions]
| ["typescript", TypeScriptPluginOptions];
type PluginConfig = Plugin$1 | ParserPluginWithOptions;
interface DecoratorsPluginOptions {
decoratorsBeforeExport?: boolean;
allowCallParenthesized?: boolean;
}
interface PipelineOperatorPluginOptions {
proposal: BABEL_8_BREAKING extends false
? "minimal" | "fsharp" | "hack" | "smart"
: "fsharp" | "hack";
topicToken?: "%" | "#" | "@@" | "^^" | "^";
}
interface RecordAndTuplePluginOptions {
syntaxType: "bar" | "hash";
}
type FlowPluginOptions = BABEL_8_BREAKING extends true
? {
all?: boolean;
enums?: boolean;
}
: {
all?: boolean;
};
interface TypeScriptPluginOptions {
dts?: boolean;
disallowAmbiguousJSXLike?: boolean;
}
type Plugin = PluginConfig;
type SourceType = "script" | "commonjs" | "module" | "unambiguous";
interface Options {
/**
* By default, import and export declarations can only appear at a program's top level.
* Setting this option to true allows them anywhere where a statement is allowed.
*/
allowImportExportEverywhere?: boolean;
/**
* By default, await use is not allowed outside of an async function.
* Set this to true to accept such code.
*/
allowAwaitOutsideFunction?: boolean;
/**
* By default, a return statement at the top level raises an error.
* Set this to true to accept such code.
*/
allowReturnOutsideFunction?: boolean;
/**
* By default, new.target use is not allowed outside of a function or class.
* Set this to true to accept such code.
*/
allowNewTargetOutsideFunction?: boolean;
allowSuperOutsideMethod?: boolean;
/**
* By default, exported identifiers must refer to a declared variable.
* Set this to true to allow export statements to reference undeclared variables.
*/
allowUndeclaredExports?: boolean;
/**
* By default, yield use is not allowed outside of a generator function.
* Set this to true to accept such code.
*/
allowYieldOutsideFunction?: boolean;
/**
* By default, Babel parser JavaScript code according to Annex B syntax.
* Set this to `false` to disable such behavior.
*/
annexB?: boolean;
/**
* By default, Babel attaches comments to adjacent AST nodes.
* When this option is set to false, comments are not attached.
* It can provide up to 30% performance improvement when the input code has many comments.
* @babel/eslint-parser will set it for you.
* It is not recommended to use attachComment: false with Babel transform,
* as doing so removes all the comments in output code, and renders annotations such as
* /* istanbul ignore next *\/ nonfunctional.
*/
attachComment?: boolean;
/**
* By default, Babel always throws an error when it finds some invalid code.
* When this option is set to true, it will store the parsing error and
* try to continue parsing the invalid input file.
*/
errorRecovery?: boolean;
/**
* Indicate the mode the code should be parsed in.
* Can be one of "script", "commonjs", "module", or "unambiguous". Defaults to "script".
* "unambiguous" will make @babel/parser attempt to guess, based on the presence
* of ES6 import or export statements.
* Files with ES6 imports and exports are considered "module" and are otherwise "script".
*
* Use "commonjs" to parse code that is intended to be run in a CommonJS environment such as Node.js.
*/
sourceType?: SourceType;
/**
* Correlate output AST nodes with their source filename.
* Useful when generating code and source maps from the ASTs of multiple input files.
*/
sourceFilename?: string;
/**
* By default, all source indexes start from 0.
* You can provide a start index to alternatively start with.
* Useful for integration with other source tools.
*/
startIndex?: number;
/**
* By default, the first line of code parsed is treated as line 1.
* You can provide a line number to alternatively start with.
* Useful for integration with other source tools.
*/
startLine?: number;
/**
* By default, the parsed code is treated as if it starts from line 1, column 0.
* You can provide a column number to alternatively start with.
* Useful for integration with other source tools.
*/
startColumn?: number;
/**
* Array containing the plugins that you want to enable.
*/
plugins?: Plugin[];
/**
* Should the parser work in strict mode.
* Defaults to true if sourceType === 'module'. Otherwise, false.
*/
strictMode?: boolean;
/**
* Adds a ranges property to each node: [node.start, node.end]
*/
ranges?: boolean;
/**
* Adds all parsed tokens to a tokens property on the File node.
*/
tokens?: boolean;
/**
* By default, the parser adds information about parentheses by setting
* `extra.parenthesized` to `true` as needed.
* When this option is `true` the parser creates `ParenthesizedExpression`
* AST nodes instead of using the `extra` property.
*/
createParenthesizedExpressions?: boolean;
/**
* The default is false in Babel 7 and true in Babel 8
* Set this to true to parse it as an `ImportExpression` node.
* Otherwise `import(foo)` is parsed as `CallExpression(Import, [Identifier(foo)])`.
*/
createImportExpressions?: boolean;
}
type ParserOptions = Partial<Options>;
interface ParseError {
code: string;
reasonCode: string;
}
type ParseResult<Result extends File | Expression = File> = Result & {
errors: null | ParseError[];
};
/**
* Parse the provided code as an entire ECMAScript program.
*/
declare function parse(input: string, options?: ParserOptions): ParseResult<File>;
declare function parseExpression(input: string, options?: ParserOptions): ParseResult<Expression>;
declare const tokTypes: {
// todo(flow->ts) real token type
[name: string]: any;
};
export { DecoratorsPluginOptions, FlowPluginOptions, ParseError, ParseResult, ParserOptions, PluginConfig as ParserPlugin, ParserPluginWithOptions, PipelineOperatorPluginOptions, RecordAndTuplePluginOptions, TypeScriptPluginOptions, parse, parseExpression, tokTypes };

22
pmoupnp/webapp/node_modules/@babel/types/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
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.

19
pmoupnp/webapp/node_modules/@babel/types/README.md generated vendored Normal file
View File

@@ -0,0 +1,19 @@
# @babel/types
> Babel Types is a Lodash-esque utility library for AST nodes
See our website [@babel/types](https://babeljs.io/docs/babel-types) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20types%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/types
```
or using yarn:
```sh
yarn add @babel/types --dev
```

View File

@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = assertNode;
var _isNode = require("../validators/isNode.js");
function assertNode(node) {
if (!(0, _isNode.default)(node)) {
var _node$type;
const type = (_node$type = node == null ? void 0 : node.type) != null ? _node$type : JSON.stringify(node);
throw new TypeError(`Not a valid node of type "${type}"`);
}
}
//# sourceMappingURL=assertNode.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_isNode","require","assertNode","node","isNode","_node$type","type","JSON","stringify","TypeError"],"sources":["../../src/asserts/assertNode.ts"],"sourcesContent":["import isNode from \"../validators/isNode.ts\";\nimport type * as t from \"../index.ts\";\n\nexport default function assertNode(node?: any): asserts node is t.Node {\n if (!isNode(node)) {\n const type = node?.type ?? JSON.stringify(node);\n throw new TypeError(`Not a valid node of type \"${type}\"`);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAGe,SAASC,UAAUA,CAACC,IAAU,EAA0B;EACrE,IAAI,CAAC,IAAAC,eAAM,EAACD,IAAI,CAAC,EAAE;IAAA,IAAAE,UAAA;IACjB,MAAMC,IAAI,IAAAD,UAAA,GAAGF,IAAI,oBAAJA,IAAI,CAAEG,IAAI,YAAAD,UAAA,GAAIE,IAAI,CAACC,SAAS,CAACL,IAAI,CAAC;IAC/C,MAAM,IAAIM,SAAS,CAAC,6BAA6BH,IAAI,GAAG,CAAC;EAC3D;AACF","ignoreList":[]}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
"use strict";
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createFlowUnionType;
var _index = require("../generated/index.js");
var _removeTypeDuplicates = require("../../modifications/flow/removeTypeDuplicates.js");
function createFlowUnionType(types) {
const flattened = (0, _removeTypeDuplicates.default)(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return (0, _index.unionTypeAnnotation)(flattened);
}
}
//# sourceMappingURL=createFlowUnionType.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_index","require","_removeTypeDuplicates","createFlowUnionType","types","flattened","removeTypeDuplicates","length","unionTypeAnnotation"],"sources":["../../../src/builders/flow/createFlowUnionType.ts"],"sourcesContent":["import { unionTypeAnnotation } from \"../generated/index.ts\";\nimport removeTypeDuplicates from \"../../modifications/flow/removeTypeDuplicates.ts\";\nimport type * as t from \"../../index.ts\";\n\n/**\n * Takes an array of `types` and flattens them, removing duplicates and\n * returns a `UnionTypeAnnotation` node containing them.\n */\nexport default function createFlowUnionType<T extends t.FlowType>(\n types: [T] | Array<T>,\n): T | t.UnionTypeAnnotation {\n const flattened = removeTypeDuplicates(types);\n\n if (flattened.length === 1) {\n return flattened[0] as T;\n } else {\n return unionTypeAnnotation(flattened);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AAOe,SAASE,mBAAmBA,CACzCC,KAAqB,EACM;EAC3B,MAAMC,SAAS,GAAG,IAAAC,6BAAoB,EAACF,KAAK,CAAC;EAE7C,IAAIC,SAAS,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,OAAOF,SAAS,CAAC,CAAC,CAAC;EACrB,CAAC,MAAM;IACL,OAAO,IAAAG,0BAAmB,EAACH,SAAS,CAAC;EACvC;AACF","ignoreList":[]}

View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = require("../generated/index.js");
var _default = exports.default = createTypeAnnotationBasedOnTypeof;
function createTypeAnnotationBasedOnTypeof(type) {
switch (type) {
case "string":
return (0, _index.stringTypeAnnotation)();
case "number":
return (0, _index.numberTypeAnnotation)();
case "undefined":
return (0, _index.voidTypeAnnotation)();
case "boolean":
return (0, _index.booleanTypeAnnotation)();
case "function":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Function"));
case "object":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Object"));
case "symbol":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Symbol"));
case "bigint":
return (0, _index.anyTypeAnnotation)();
}
throw new Error("Invalid typeof value: " + type);
}
//# sourceMappingURL=createTypeAnnotationBasedOnTypeof.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_index","require","_default","exports","default","createTypeAnnotationBasedOnTypeof","type","stringTypeAnnotation","numberTypeAnnotation","voidTypeAnnotation","booleanTypeAnnotation","genericTypeAnnotation","identifier","anyTypeAnnotation","Error"],"sources":["../../../src/builders/flow/createTypeAnnotationBasedOnTypeof.ts"],"sourcesContent":["import {\n anyTypeAnnotation,\n stringTypeAnnotation,\n numberTypeAnnotation,\n voidTypeAnnotation,\n booleanTypeAnnotation,\n genericTypeAnnotation,\n identifier,\n} from \"../generated/index.ts\";\nimport type * as t from \"../../index.ts\";\n\nexport default createTypeAnnotationBasedOnTypeof as {\n (type: \"string\"): t.StringTypeAnnotation;\n (type: \"number\"): t.NumberTypeAnnotation;\n (type: \"undefined\"): t.VoidTypeAnnotation;\n (type: \"boolean\"): t.BooleanTypeAnnotation;\n (type: \"function\"): t.GenericTypeAnnotation;\n (type: \"object\"): t.GenericTypeAnnotation;\n (type: \"symbol\"): t.GenericTypeAnnotation;\n (type: \"bigint\"): t.AnyTypeAnnotation;\n};\n\n/**\n * Create a type annotation based on typeof expression.\n */\nfunction createTypeAnnotationBasedOnTypeof(type: string): t.FlowType {\n switch (type) {\n case \"string\":\n return stringTypeAnnotation();\n case \"number\":\n return numberTypeAnnotation();\n case \"undefined\":\n return voidTypeAnnotation();\n case \"boolean\":\n return booleanTypeAnnotation();\n case \"function\":\n return genericTypeAnnotation(identifier(\"Function\"));\n case \"object\":\n return genericTypeAnnotation(identifier(\"Object\"));\n case \"symbol\":\n return genericTypeAnnotation(identifier(\"Symbol\"));\n case \"bigint\":\n // todo: use BigInt annotation when Flow supports BigInt\n // https://github.com/facebook/flow/issues/6639\n return anyTypeAnnotation();\n }\n throw new Error(\"Invalid typeof value: \" + type);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAQ+B,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAGhBC,iCAAiC;AAchD,SAASA,iCAAiCA,CAACC,IAAY,EAAc;EACnE,QAAQA,IAAI;IACV,KAAK,QAAQ;MACX,OAAO,IAAAC,2BAAoB,EAAC,CAAC;IAC/B,KAAK,QAAQ;MACX,OAAO,IAAAC,2BAAoB,EAAC,CAAC;IAC/B,KAAK,WAAW;MACd,OAAO,IAAAC,yBAAkB,EAAC,CAAC;IAC7B,KAAK,SAAS;MACZ,OAAO,IAAAC,4BAAqB,EAAC,CAAC;IAChC,KAAK,UAAU;MACb,OAAO,IAAAC,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,UAAU,CAAC,CAAC;IACtD,KAAK,QAAQ;MACX,OAAO,IAAAD,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,QAAQ,CAAC,CAAC;IACpD,KAAK,QAAQ;MACX,OAAO,IAAAD,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,QAAQ,CAAC,CAAC;IACpD,KAAK,QAAQ;MAGX,OAAO,IAAAC,wBAAiB,EAAC,CAAC;EAC9B;EACA,MAAM,IAAIC,KAAK,CAAC,wBAAwB,GAAGR,IAAI,CAAC;AAClD","ignoreList":[]}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _lowercase = require("./lowercase.js");
Object.keys(_lowercase).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _lowercase[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _lowercase[key];
}
});
});
var _uppercase = require("./uppercase.js");
Object.keys(_uppercase).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _uppercase[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _uppercase[key];
}
});
});
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More