+
```
+As per the given HTML snippet, remember to place the data attributes for values on the same element as the `data-controller` attribute.
+
@@ -53,13 +54,13 @@ export default class extends Controller {
A value's type is one of `Array`, `Boolean`, `Number`, `Object`, or `String`. The type determines how the value is transcoded between JavaScript and HTML.
-Type | Encoded as… | Decoded as…
----- | ----------- | -----------
-Array | `JSON.stringify(array)` | `JSON.parse(value)`
-Boolean | `boolean.toString()` | `!(value == "0" \|\| value == "false")`
-Number | `number.toString()` | `Number(value)`
-Object | `JSON.stringify(object)` | `JSON.parse(value)`
-String | Itself | Itself
+| Type | Encoded as… | Decoded as… |
+| ------- | ------------------------ | --------------------------------------- |
+| Array | `JSON.stringify(array)` | `JSON.parse(value)` |
+| Boolean | `boolean.toString()` | `!(value == "0" \|\| value == "false")` |
+| Number | `number.toString()` | `Number(value.replace(/_/g, ""))` |
+| Object | `JSON.stringify(object)` | `JSON.parse(value)` |
+| String | Itself | Itself |
## Properties and Attributes
diff --git a/examples/package.json b/examples/package.json
index ad465189..a7f40ff6 100644
--- a/examples/package.json
+++ b/examples/package.json
@@ -10,7 +10,7 @@
"@hotwired/turbo": "^7.2.4",
"babel-loader": "^8.0.6",
"ejs": "^3.1.7",
- "express": "^4.16.3",
+ "express": "^4.17.3",
"webpack": "^4.39.1",
"webpack-dev-middleware": "^3.7.0"
},
diff --git a/examples/yarn.lock b/examples/yarn.lock
index dda0899f..3736b274 100644
--- a/examples/yarn.lock
+++ b/examples/yarn.lock
@@ -1045,13 +1045,13 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
-accepts@~1.3.7:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
- integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
dependencies:
- mime-types "~2.1.24"
- negotiator "0.6.2"
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
acorn@^6.4.1:
version "6.4.2"
@@ -1282,21 +1282,21 @@ bn.js@^5.0.0, bn.js@^5.1.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
-body-parser@1.19.0:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
- integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+body-parser@1.19.2:
+ version "1.19.2"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
+ integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==
dependencies:
- bytes "3.1.0"
+ bytes "3.1.2"
content-type "~1.0.4"
debug "2.6.9"
depd "~1.1.2"
- http-errors "1.7.2"
+ http-errors "1.8.1"
iconv-lite "0.4.24"
on-finished "~2.3.0"
- qs "6.7.0"
- raw-body "2.4.0"
- type-is "~1.6.17"
+ qs "6.9.7"
+ raw-body "2.4.3"
+ type-is "~1.6.18"
brace-expansion@^1.1.7:
version "1.1.11"
@@ -1437,10 +1437,10 @@ builtin-status-codes@^3.0.0:
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
-bytes@3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
- integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
cacache@^12.0.2:
version "12.0.4"
@@ -1647,12 +1647,12 @@ constants-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
-content-disposition@0.5.3:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
- integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
dependencies:
- safe-buffer "5.1.2"
+ safe-buffer "5.2.1"
content-type@~1.0.4:
version "1.0.4"
@@ -1671,10 +1671,10 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-cookie@0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
- integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+cookie@0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+ integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
copy-concurrently@^1.0.0:
version "1.0.5"
@@ -1774,9 +1774,9 @@ debug@^4.1.0, debug@^4.1.1:
ms "2.1.2"
decode-uri-component@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
- integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
+ integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
define-properties@^1.1.3:
version "1.1.3"
@@ -1988,17 +1988,17 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-express@^4.16.3:
- version "4.17.1"
- resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
- integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+express@^4.17.3:
+ version "4.17.3"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
+ integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
dependencies:
- accepts "~1.3.7"
+ accepts "~1.3.8"
array-flatten "1.1.1"
- body-parser "1.19.0"
- content-disposition "0.5.3"
+ body-parser "1.19.2"
+ content-disposition "0.5.4"
content-type "~1.0.4"
- cookie "0.4.0"
+ cookie "0.4.2"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
@@ -2012,13 +2012,13 @@ express@^4.16.3:
on-finished "~2.3.0"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
- proxy-addr "~2.0.5"
- qs "6.7.0"
+ proxy-addr "~2.0.7"
+ qs "6.9.7"
range-parser "~1.2.1"
- safe-buffer "5.1.2"
- send "0.17.1"
- serve-static "1.14.1"
- setprototypeof "1.1.1"
+ safe-buffer "5.2.1"
+ send "0.17.2"
+ serve-static "1.14.2"
+ setprototypeof "1.2.0"
statuses "~1.5.0"
type-is "~1.6.18"
utils-merge "1.0.1"
@@ -2349,27 +2349,16 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-http-errors@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
- integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-errors@~1.7.2:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
- integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
+http-errors@1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
+ integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
dependencies:
depd "~1.1.2"
inherits "2.0.4"
- setprototypeof "1.1.1"
+ setprototypeof "1.2.0"
statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
+ toidentifier "1.0.1"
https-browserify@^1.0.0:
version "1.0.0"
@@ -2616,9 +2605,9 @@ json-schema-traverse@^0.4.1:
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json5@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
- integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
+ integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
dependencies:
minimist "^1.2.0"
@@ -2793,6 +2782,11 @@ mime-db@1.48.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d"
integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
mime-types@~2.1.24:
version "2.1.31"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b"
@@ -2800,6 +2794,13 @@ mime-types@~2.1.24:
dependencies:
mime-db "1.48.0"
+mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
mime@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@@ -2835,9 +2836,9 @@ minimatch@^5.0.1:
brace-expansion "^2.0.1"
minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
- integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
+ integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
mississippi@^3.0.0:
version "3.0.0"
@@ -2887,16 +2888,16 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-ms@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
- integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+ms@2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
nan@^2.12.1:
version "2.15.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
@@ -2919,10 +2920,10 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-negotiator@0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
- integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
neo-async@^2.5.0, neo-async@^2.6.1:
version "2.6.2"
@@ -3188,7 +3189,7 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
-proxy-addr@~2.0.5:
+proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
@@ -3253,10 +3254,10 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-qs@6.7.0:
- version "6.7.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
- integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+qs@6.9.7:
+ version "6.9.7"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
+ integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
querystring-es3@^0.2.0:
version "0.2.1"
@@ -3288,13 +3289,13 @@ range-parser@^1.2.1, range-parser@~1.2.1:
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
-raw-body@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
- integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+raw-body@2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
+ integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
dependencies:
- bytes "3.1.0"
- http-errors "1.7.2"
+ bytes "3.1.2"
+ http-errors "1.8.1"
iconv-lite "0.4.24"
unpipe "1.0.0"
@@ -3447,16 +3448,16 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
-safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
safe-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
@@ -3493,19 +3494,19 @@ semver@7.0.0:
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^5.6.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-send@0.17.1:
- version "0.17.1"
- resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
- integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+send@0.17.2:
+ version "0.17.2"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
+ integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==
dependencies:
debug "2.6.9"
depd "~1.1.2"
@@ -3514,9 +3515,9 @@ send@0.17.1:
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
- http-errors "~1.7.2"
+ http-errors "1.8.1"
mime "1.6.0"
- ms "2.1.1"
+ ms "2.1.3"
on-finished "~2.3.0"
range-parser "~1.2.1"
statuses "~1.5.0"
@@ -3528,15 +3529,15 @@ serialize-javascript@^4.0.0:
dependencies:
randombytes "^2.1.0"
-serve-static@1.14.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
- integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+serve-static@1.14.2:
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa"
+ integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
- send "0.17.1"
+ send "0.17.2"
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
@@ -3553,10 +3554,10 @@ setimmediate@^1.0.4:
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
-setprototypeof@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
- integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
sha.js@^2.4.0, sha.js@^2.4.8:
version "2.4.11"
@@ -3808,17 +3809,17 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
-toidentifier@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
- integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
-type-is@~1.6.17, type-is@~1.6.18:
+type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
diff --git a/package.json b/package.json
index 686cfad7..4db96b08 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hotwired/stimulus",
- "version": "3.2.1",
+ "version": "3.2.2",
"license": "MIT",
"description": "A modest JavaScript framework for the HTML you already have.",
"author": "Basecamp, LLC",
@@ -31,10 +31,11 @@
"scripts": {
"clean": "rm -fr dist",
"types": "tsc --noEmit false --declaration true --emitDeclarationOnly true --outDir dist/types",
+ "prebuild": "yarn build:test",
"build": "yarn types && rollup -c",
"build:test": "tsc -b tsconfig.test.json",
"watch": "rollup -wc",
- "prerelease": "yarn build && git --no-pager diff && echo && npm pack --dry-run",
+ "prerelease": "yarn clean && yarn build && yarn build:test && git --no-pager diff && echo && npm pack --dry-run",
"release": "npm publish",
"start": "concurrently \"npm:watch\" \"npm:start:examples\"",
"start:examples": "cd examples && yarn install && node server.js",
@@ -45,28 +46,28 @@
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^13.0.0",
- "@rollup/plugin-typescript": "^8.5.0",
+ "@rollup/plugin-typescript": "^11.1.1",
"@types/qunit": "^2.9.0",
"@types/webpack-env": "^1.14.0",
- "@typescript-eslint/eslint-plugin": "^5.36.2",
- "@typescript-eslint/parser": "^5.36.2",
+ "@typescript-eslint/eslint-plugin": "^5.59.11",
+ "@typescript-eslint/parser": "^5.59.11",
"concurrently": "^6.2.1",
- "eslint": "^8.23.0",
- "eslint-config-prettier": "^8.5.0",
+ "eslint": "^8.43.0",
+ "eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"karma": "^6.4.1",
"karma-chrome-launcher": "^3.1.1",
"karma-qunit": "^4.1.2",
"karma-sauce-launcher": "^4.3.6",
"karma-webpack": "^4.0.2",
- "prettier": "^2.7.1",
+ "prettier": "^2.8.8",
"qunit": "^2.9.2",
"rimraf": "^3.0.2",
"rollup": "^2.53",
"rollup-plugin-terser": "^7.0.2",
- "ts-loader": "^6.0.4",
- "tslib": "^2.4.0",
- "typescript": "^4.8.2",
+ "ts-loader": "^9.4.3",
+ "tslib": "^2.5.3",
+ "typescript": "^5.1.3",
"webpack": "^4.39.1"
},
"resolutions": {
diff --git a/packages/stimulus/package.json b/packages/stimulus/package.json
index b8676752..a0b1d90a 100644
--- a/packages/stimulus/package.json
+++ b/packages/stimulus/package.json
@@ -1,6 +1,6 @@
{
"name": "stimulus",
- "version": "3.2.1",
+ "version": "3.2.2",
"description": "Stimulus JavaScript framework",
"repository": "https://stimulus.hotwired.dev",
"author": "Basecamp, LLC",
@@ -42,7 +42,7 @@
],
"license": "MIT",
"dependencies": {
- "@hotwired/stimulus": "^3.2.1",
+ "@hotwired/stimulus": "^3.2.2",
"@hotwired/stimulus-webpack-helpers": "^1.0.0"
},
"devDependencies": {
diff --git a/packages/stimulus/yarn.lock b/packages/stimulus/yarn.lock
index 6ccf538b..7f97d8d0 100644
--- a/packages/stimulus/yarn.lock
+++ b/packages/stimulus/yarn.lock
@@ -7,10 +7,10 @@
resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.0.tgz#6bd7906a4a2b6e1cd8732203b60264f987bd1084"
integrity sha512-6oKDmJDSsV+zdlHnF485nneuekY/Zbl669wei4HIiwxUWHhVSU1XIVji4aj+Ws9AXghjTYBS8H5ralB97BVMDw==
-"@hotwired/stimulus@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.0.tgz#257272f1348b1f7beb1a8510be88b80aec6c4c5b"
- integrity sha512-uAIIdg049qId0lBhyjuMBfcC5uV8JwbhNLoxEyi9vxM3MW6h+mM97G9rNT4ZZMiqnKK9XUHp9SQUrd9rSLEmpQ==
+"@hotwired/stimulus@^3.2.2":
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608"
+ integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A==
"@rollup/plugin-node-resolve@^13.0.0":
version "13.0.5"
diff --git a/src/core/action.ts b/src/core/action.ts
index 8fba7a10..e009399b 100644
--- a/src/core/action.ts
+++ b/src/core/action.ts
@@ -2,6 +2,10 @@ import { ActionDescriptor, parseActionDescriptorString, stringifyEventTarget } f
import { Token } from "../mutation-observers"
import { Schema } from "./schema"
import { camelize } from "./string_helpers"
+import { hasProperty } from "./utils"
+
+const allModifiers = ["meta", "ctrl", "alt", "shift"]
+
export class Action {
readonly element: Element
readonly index: number
@@ -35,32 +39,42 @@ export class Action {
return `${this.eventName}${eventFilter}${eventTarget}->${this.identifier}#${this.methodName}`
}
- isFilterTarget(event: KeyboardEvent): boolean {
+ shouldIgnoreKeyboardEvent(event: KeyboardEvent): boolean {
if (!this.keyFilter) {
return false
}
- const filteres = this.keyFilter.split("+")
- const modifiers = ["meta", "ctrl", "alt", "shift"]
- const [meta, ctrl, alt, shift] = modifiers.map((modifier) => filteres.includes(modifier))
-
- if (event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== alt || event.shiftKey !== shift) {
+ const filters = this.keyFilter.split("+")
+ if (this.keyFilterDissatisfied(event, filters)) {
return true
}
- const standardFilter = filteres.filter((key) => !modifiers.includes(key))[0]
+ const standardFilter = filters.filter((key) => !allModifiers.includes(key))[0]
if (!standardFilter) {
// missing non modifier key
return false
}
- if (!Object.prototype.hasOwnProperty.call(this.keyMappings, standardFilter)) {
+ if (!hasProperty(this.keyMappings, standardFilter)) {
error(`contains unknown key filter: ${this.keyFilter}`)
}
return this.keyMappings[standardFilter].toLowerCase() !== event.key.toLowerCase()
}
+ shouldIgnoreMouseEvent(event: MouseEvent): boolean {
+ if (!this.keyFilter) {
+ return false
+ }
+
+ const filters = [this.keyFilter]
+ if (this.keyFilterDissatisfied(event, filters)) {
+ return true
+ }
+
+ return false
+ }
+
get params() {
const params: { [key: string]: any } = {}
const pattern = new RegExp(`^data-${this.identifier}-(.+)-param$`, "i")
@@ -82,6 +96,12 @@ export class Action {
private get keyMappings() {
return this.schema.keyMappings
}
+
+ private keyFilterDissatisfied(event: KeyboardEvent | MouseEvent, filters: Array
): boolean {
+ const [meta, ctrl, alt, shift] = allModifiers.map((modifier) => filters.includes(modifier))
+
+ return event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== alt || event.shiftKey !== shift
+ }
}
const defaultEventNames: { [tagName: string]: (element: Element) => string } = {
diff --git a/src/core/action_descriptor.ts b/src/core/action_descriptor.ts
index fe051981..35a4a211 100644
--- a/src/core/action_descriptor.ts
+++ b/src/core/action_descriptor.ts
@@ -1,3 +1,5 @@
+import type { Controller } from "./controller"
+
export type ActionDescriptorFilters = Record
export type ActionDescriptorFilter = (options: ActionDescriptorFilterOptions) => boolean
type ActionDescriptorFilterOptions = {
@@ -5,6 +7,7 @@ type ActionDescriptorFilterOptions = {
value: boolean
event: Event
element: Element
+ controller: Controller
}
export const defaultActionDescriptorFilters: ActionDescriptorFilters = {
@@ -38,14 +41,14 @@ export interface ActionDescriptor {
keyFilter: string
}
-// capture nos.: 1 1 2 2 3 3 4 4 5 5 6 6
-const descriptorPattern = /^(?:(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/
+// capture nos.: 1 1 2 2 3 3 4 4 5 5 6 6 7 7
+const descriptorPattern = /^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/
export function parseActionDescriptorString(descriptorString: string): Partial {
const source = descriptorString.trim()
const matches = source.match(descriptorPattern) || []
- let eventName = matches[1]
- let keyFilter = matches[2]
+ let eventName = matches[2]
+ let keyFilter = matches[3]
if (keyFilter && !["keydown", "keyup", "keypress"].includes(eventName)) {
eventName += `.${keyFilter}`
@@ -53,12 +56,12 @@ export function parseActionDescriptorString(descriptorString: string): Partial
+type DispatchOptions = Partial<{
+ target: Element | Window | Document
+ detail: Object
+ prefix: string
+ bubbles: boolean
+ cancelable: boolean
+}>
+
export class Controller {
static blessings = [
ClassPropertiesBlessing,
@@ -79,7 +87,13 @@ export class Controller {
dispatch(
eventName: string,
- { target = this.element, detail = {}, prefix = this.identifier, bubbles = true, cancelable = true } = {}
+ {
+ target = this.element,
+ detail = {},
+ prefix = this.identifier,
+ bubbles = true,
+ cancelable = true,
+ }: DispatchOptions = {}
) {
const type = prefix ? `${prefix}:${eventName}` : eventName
const event = new CustomEvent(type, { detail, bubbles, cancelable })
diff --git a/src/core/outlet_observer.ts b/src/core/outlet_observer.ts
index 0208129f..b0956f47 100644
--- a/src/core/outlet_observer.ts
+++ b/src/core/outlet_observer.ts
@@ -1,64 +1,79 @@
import { Multimap } from "../multimap"
+import { AttributeObserver, AttributeObserverDelegate } from "../mutation-observers"
import { SelectorObserver, SelectorObserverDelegate } from "../mutation-observers"
import { Context } from "./context"
import { Controller } from "./controller"
import { readInheritableStaticArrayValues } from "./inheritable_statics"
-type SelectorObserverDetails = { outletName: string }
+type OutletObserverDetails = { outletName: string }
export interface OutletObserverDelegate {
outletConnected(outlet: Controller, element: Element, outletName: string): void
outletDisconnected(outlet: Controller, element: Element, outletName: string): void
}
-export class OutletObserver implements SelectorObserverDelegate {
+export class OutletObserver implements AttributeObserverDelegate, SelectorObserverDelegate {
+ started: boolean
readonly context: Context
readonly delegate: OutletObserverDelegate
readonly outletsByName: Multimap
readonly outletElementsByName: Multimap
private selectorObserverMap: Map
+ private attributeObserverMap: Map
constructor(context: Context, delegate: OutletObserverDelegate) {
+ this.started = false
this.context = context
this.delegate = delegate
this.outletsByName = new Multimap()
this.outletElementsByName = new Multimap()
this.selectorObserverMap = new Map()
+ this.attributeObserverMap = new Map()
}
start() {
- if (this.selectorObserverMap.size === 0) {
+ if (!this.started) {
this.outletDefinitions.forEach((outletName) => {
- const selector = this.selector(outletName)
- const details: SelectorObserverDetails = { outletName }
-
- if (selector) {
- this.selectorObserverMap.set(outletName, new SelectorObserver(document.body, selector, this, details))
- }
+ this.setupSelectorObserverForOutlet(outletName)
+ this.setupAttributeObserverForOutlet(outletName)
})
-
- this.selectorObserverMap.forEach((observer) => observer.start())
+ this.started = true
+ this.dependentContexts.forEach((context) => context.refresh())
}
+ }
- this.dependentContexts.forEach((context) => context.refresh())
+ refresh() {
+ this.selectorObserverMap.forEach((observer) => observer.refresh())
+ this.attributeObserverMap.forEach((observer) => observer.refresh())
}
stop() {
- if (this.selectorObserverMap.size > 0) {
+ if (this.started) {
+ this.started = false
this.disconnectAllOutlets()
+ this.stopSelectorObservers()
+ this.stopAttributeObservers()
+ }
+ }
+
+ stopSelectorObservers() {
+ if (this.selectorObserverMap.size > 0) {
this.selectorObserverMap.forEach((observer) => observer.stop())
this.selectorObserverMap.clear()
}
}
- refresh() {
- this.selectorObserverMap.forEach((observer) => observer.refresh())
+ stopAttributeObservers() {
+ if (this.attributeObserverMap.size > 0) {
+ this.attributeObserverMap.forEach((observer) => observer.stop())
+ this.attributeObserverMap.clear()
+ }
}
// Selector observer delegate
- selectorMatched(element: Element, _selector: string, { outletName }: SelectorObserverDetails) {
+ selectorMatched(element: Element, _selector: string, { outletName }: OutletObserverDetails) {
const outlet = this.getOutlet(element, outletName)
if (outlet) {
@@ -66,7 +81,7 @@ export class OutletObserver implements SelectorObserverDelegate {
}
}
- selectorUnmatched(element: Element, _selector: string, { outletName }: SelectorObserverDetails) {
+ selectorUnmatched(element: Element, _selector: string, { outletName }: OutletObserverDetails) {
const outlet = this.getOutletFromMap(element, outletName)
if (outlet) {
@@ -74,11 +89,42 @@ export class OutletObserver implements SelectorObserverDelegate {
}
}
- selectorMatchElement(element: Element, { outletName }: SelectorObserverDetails) {
- return (
- this.hasOutlet(element, outletName) &&
- element.matches(`[${this.context.application.schema.controllerAttribute}~=${outletName}]`)
- )
+ selectorMatchElement(element: Element, { outletName }: OutletObserverDetails) {
+ const selector = this.selector(outletName)
+ const hasOutlet = this.hasOutlet(element, outletName)
+ const hasOutletController = element.matches(`[${this.schema.controllerAttribute}~=${outletName}]`)
+
+ if (selector) {
+ return hasOutlet && hasOutletController && element.matches(selector)
+ } else {
+ return false
+ }
+ }
+
+ // Attribute observer delegate
+
+ elementMatchedAttribute(_element: Element, attributeName: string) {
+ const outletName = this.getOutletNameFromOutletAttributeName(attributeName)
+
+ if (outletName) {
+ this.updateSelectorObserverForOutlet(outletName)
+ }
+ }
+
+ elementAttributeValueChanged(_element: Element, attributeName: string) {
+ const outletName = this.getOutletNameFromOutletAttributeName(attributeName)
+
+ if (outletName) {
+ this.updateSelectorObserverForOutlet(outletName)
+ }
+ }
+
+ elementUnmatchedAttribute(_element: Element, attributeName: string) {
+ const outletName = this.getOutletNameFromOutletAttributeName(attributeName)
+
+ if (outletName) {
+ this.updateSelectorObserverForOutlet(outletName)
+ }
}
// Outlet management
@@ -111,12 +157,48 @@ export class OutletObserver implements SelectorObserverDelegate {
}
}
+ // Observer management
+
+ private updateSelectorObserverForOutlet(outletName: string) {
+ const observer = this.selectorObserverMap.get(outletName)
+
+ if (observer) {
+ observer.selector = this.selector(outletName)
+ }
+ }
+
+ private setupSelectorObserverForOutlet(outletName: string) {
+ const selector = this.selector(outletName)
+ const selectorObserver = new SelectorObserver(document.body, selector!, this, { outletName })
+
+ this.selectorObserverMap.set(outletName, selectorObserver)
+
+ selectorObserver.start()
+ }
+
+ private setupAttributeObserverForOutlet(outletName: string) {
+ const attributeName = this.attributeNameForOutletName(outletName)
+ const attributeObserver = new AttributeObserver(this.scope.element, attributeName, this)
+
+ this.attributeObserverMap.set(outletName, attributeObserver)
+
+ attributeObserver.start()
+ }
+
// Private
private selector(outletName: string) {
return this.scope.outlets.getSelectorForOutletName(outletName)
}
+ private attributeNameForOutletName(outletName: string) {
+ return this.scope.schema.outletAttributeForScope(this.identifier, outletName)
+ }
+
+ private getOutletNameFromOutletAttributeName(attributeName: string) {
+ return this.outletDefinitions.find((outletName) => this.attributeNameForOutletName(outletName) === attributeName)
+ }
+
private get outletDependencies() {
const dependencies = new Multimap()
@@ -159,6 +241,10 @@ export class OutletObserver implements SelectorObserverDelegate {
return this.context.scope
}
+ private get schema() {
+ return this.context.schema
+ }
+
private get identifier() {
return this.context.identifier
}
diff --git a/src/core/outlet_properties.ts b/src/core/outlet_properties.ts
index 3fe7928d..4af436a4 100644
--- a/src/core/outlet_properties.ts
+++ b/src/core/outlet_properties.ts
@@ -10,26 +10,42 @@ export function OutletPropertiesBlessing(constructor: Constructor) {
}, {} as PropertyDescriptorMap)
}
+function getOutletController(controller: Controller, element: Element, identifier: string) {
+ return controller.application.getControllerForElementAndIdentifier(element, identifier)
+}
+
+function getControllerAndEnsureConnectedScope(controller: Controller, element: Element, outletName: string) {
+ let outletController = getOutletController(controller, element, outletName)
+ if (outletController) return outletController
+
+ controller.application.router.proposeToConnectScopeForElementAndIdentifier(element, outletName)
+
+ outletController = getOutletController(controller, element, outletName)
+ if (outletController) return outletController
+}
+
function propertiesForOutletDefinition(name: string) {
const camelizedName = namespaceCamelize(name)
return {
[`${camelizedName}Outlet`]: {
get(this: Controller) {
- const outlet = this.outlets.find(name)
-
- if (outlet) {
- const outletController = this.application.getControllerForElementAndIdentifier(outlet, name)
- if (outletController) {
- return outletController
- } else {
- throw new Error(
- `Missing "data-controller=${name}" attribute on outlet element for "${this.identifier}" controller`
- )
- }
+ const outletElement = this.outlets.find(name)
+ const selector = this.outlets.getSelectorForOutletName(name)
+
+ if (outletElement) {
+ const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name)
+
+ if (outletController) return outletController
+
+ throw new Error(
+ `The provided outlet element is missing an outlet controller "${name}" instance for host controller "${this.identifier}"`
+ )
}
- throw new Error(`Missing outlet element "${name}" for "${this.identifier}" controller`)
+ throw new Error(
+ `Missing outlet element "${name}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${selector}".`
+ )
},
},
@@ -39,16 +55,15 @@ function propertiesForOutletDefinition(name: string) {
if (outlets.length > 0) {
return outlets
- .map((outlet: Element) => {
- const controller = this.application.getControllerForElementAndIdentifier(outlet, name)
- if (controller) {
- return controller
- } else {
- console.warn(
- `The provided outlet element is missing the outlet controller "${name}" for "${this.identifier}"`,
- outlet
- )
- }
+ .map((outletElement: Element) => {
+ const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name)
+
+ if (outletController) return outletController
+
+ console.warn(
+ `The provided outlet element is missing an outlet controller "${name}" instance for host controller "${this.identifier}"`,
+ outletElement
+ )
})
.filter((controller) => controller) as Controller[]
}
@@ -59,11 +74,15 @@ function propertiesForOutletDefinition(name: string) {
[`${camelizedName}OutletElement`]: {
get(this: Controller) {
- const outlet = this.outlets.find(name)
- if (outlet) {
- return outlet
+ const outletElement = this.outlets.find(name)
+ const selector = this.outlets.getSelectorForOutletName(name)
+
+ if (outletElement) {
+ return outletElement
} else {
- throw new Error(`Missing outlet element "${name}" for "${this.identifier}" controller`)
+ throw new Error(
+ `Missing outlet element "${name}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${selector}".`
+ )
}
},
},
diff --git a/src/core/router.ts b/src/core/router.ts
index c06e5e57..d0d40a84 100644
--- a/src/core/router.ts
+++ b/src/core/router.ts
@@ -57,7 +57,7 @@ export class Router implements ScopeObserverDelegate {
this.connectModule(module)
const afterLoad = (definition.controllerConstructor as any).afterLoad
if (afterLoad) {
- afterLoad(definition.identifier, this.application)
+ afterLoad.call(definition.controllerConstructor, definition.identifier, this.application)
}
}
@@ -75,6 +75,16 @@ export class Router implements ScopeObserverDelegate {
}
}
+ proposeToConnectScopeForElementAndIdentifier(element: Element, identifier: string) {
+ const scope = this.scopeObserver.parseValueForElementAndIdentifier(element, identifier)
+
+ if (scope) {
+ this.scopeObserver.elementMatchedValue(scope.element, scope)
+ } else {
+ console.error(`Couldn't find or create scope for identifier: "${identifier}" and element:`, element)
+ }
+ }
+
// Error handler delegate
handleError(error: Error, message: string, detail: any) {
diff --git a/src/core/schema.ts b/src/core/schema.ts
index 20845d20..bbc5b24a 100644
--- a/src/core/schema.ts
+++ b/src/core/schema.ts
@@ -24,6 +24,8 @@ export const defaultSchema: Schema = {
right: "ArrowRight",
home: "Home",
end: "End",
+ page_up: "PageUp",
+ page_down: "PageDown",
// [a-z]
...objectFromEntries("abcdefghijklmnopqrstuvwxyz".split("").map((c) => [c, c])),
// [0-9]
diff --git a/src/core/scope_observer.ts b/src/core/scope_observer.ts
index 6ddcd0ef..0349a24b 100644
--- a/src/core/scope_observer.ts
+++ b/src/core/scope_observer.ts
@@ -42,6 +42,10 @@ export class ScopeObserver implements ValueListObserverDelegate {
parseValueForToken(token: Token): Scope | undefined {
const { element, content: identifier } = token
+ return this.parseValueForElementAndIdentifier(element, identifier)
+ }
+
+ parseValueForElementAndIdentifier(element: Element, identifier: string): Scope | undefined {
const scopesByIdentifier = this.fetchScopesByIdentifierForElement(element)
let scope = scopesByIdentifier.get(identifier)
diff --git a/src/core/utils.ts b/src/core/utils.ts
new file mode 100644
index 00000000..ae3a262f
--- /dev/null
+++ b/src/core/utils.ts
@@ -0,0 +1,7 @@
+export function isSomething(object: any): boolean {
+ return object !== null && object !== undefined
+}
+
+export function hasProperty(object: any, property: string): boolean {
+ return Object.prototype.hasOwnProperty.call(object, property)
+}
diff --git a/src/core/value_properties.ts b/src/core/value_properties.ts
index 6a431314..c15e2d9a 100644
--- a/src/core/value_properties.ts
+++ b/src/core/value_properties.ts
@@ -2,6 +2,7 @@ import { Constructor } from "./constructor"
import { Controller } from "./controller"
import { readInheritableStaticObjectPairs } from "./inheritable_statics"
import { camelize, capitalize, dasherize } from "./string_helpers"
+import { isSomething, hasProperty } from "./utils"
export function ValuePropertiesBlessing(constructor: Constructor) {
const valueDefinitionPairs = readInheritableStaticObjectPairs(constructor, "values")
@@ -77,7 +78,7 @@ export type ValueTypeConstant = typeof Array | typeof Boolean | typeof Number |
export type ValueTypeDefault = Array | boolean | number | Object | string
-export type ValueTypeObject = { type: ValueTypeConstant; default: ValueTypeDefault }
+export type ValueTypeObject = Partial<{ type: ValueTypeConstant; default: ValueTypeDefault }>
export type ValueTypeDefinition = ValueTypeConstant | ValueTypeDefault | ValueTypeObject
@@ -91,7 +92,7 @@ function parseValueDefinitionPair([token, typeDefinition]: ValueDefinitionPair,
})
}
-function parseValueTypeConstant(constant: ValueTypeConstant) {
+export function parseValueTypeConstant(constant?: ValueTypeConstant) {
switch (constant) {
case Array:
return "array"
@@ -106,7 +107,7 @@ function parseValueTypeConstant(constant: ValueTypeConstant) {
}
}
-function parseValueTypeDefault(defaultValue: ValueTypeDefault) {
+export function parseValueTypeDefault(defaultValue?: ValueTypeDefault) {
switch (typeof defaultValue) {
case "boolean":
return "boolean"
@@ -120,73 +121,97 @@ function parseValueTypeDefault(defaultValue: ValueTypeDefault) {
if (Object.prototype.toString.call(defaultValue) === "[object Object]") return "object"
}
-function parseValueTypeObject(payload: { controller?: string; token: string; typeObject: ValueTypeObject }) {
- const typeFromObject = parseValueTypeConstant(payload.typeObject.type)
+type ValueTypeObjectPayload = {
+ controller?: string
+ token: string
+ typeObject: ValueTypeObject
+}
+
+export function parseValueTypeObject(payload: ValueTypeObjectPayload) {
+ const { controller, token, typeObject } = payload
+
+ const hasType = isSomething(typeObject.type)
+ const hasDefault = isSomething(typeObject.default)
- if (!typeFromObject) return
+ const fullObject = hasType && hasDefault
+ const onlyType = hasType && !hasDefault
+ const onlyDefault = !hasType && hasDefault
- const defaultValueType = parseValueTypeDefault(payload.typeObject.default)
+ const typeFromObject = parseValueTypeConstant(typeObject.type)
+ const typeFromDefaultValue = parseValueTypeDefault(payload.typeObject.default)
- if (typeFromObject !== defaultValueType) {
- const propertyPath = payload.controller ? `${payload.controller}.${payload.token}` : payload.token
+ if (onlyType) return typeFromObject
+ if (onlyDefault) return typeFromDefaultValue
+
+ if (typeFromObject !== typeFromDefaultValue) {
+ const propertyPath = controller ? `${controller}.${token}` : token
throw new Error(
- `The specified default value for the Stimulus Value "${propertyPath}" must match the defined type "${typeFromObject}". The provided default value of "${payload.typeObject.default}" is of type "${defaultValueType}".`
+ `The specified default value for the Stimulus Value "${propertyPath}" must match the defined type "${typeFromObject}". The provided default value of "${typeObject.default}" is of type "${typeFromDefaultValue}".`
)
}
- return typeFromObject
+ if (fullObject) return typeFromObject
}
-function parseValueTypeDefinition(payload: {
+type ValueTypeDefinitionPayload = {
controller?: string
token: string
typeDefinition: ValueTypeDefinition
-}): ValueType {
- const typeFromObject = parseValueTypeObject({
- controller: payload.controller,
- token: payload.token,
- typeObject: payload.typeDefinition as ValueTypeObject,
- })
- const typeFromDefaultValue = parseValueTypeDefault(payload.typeDefinition as ValueTypeDefault)
- const typeFromConstant = parseValueTypeConstant(payload.typeDefinition as ValueTypeConstant)
+}
+
+export function parseValueTypeDefinition(payload: ValueTypeDefinitionPayload): ValueType {
+ const { controller, token, typeDefinition } = payload
+
+ const typeObject = { controller, token, typeObject: typeDefinition as ValueTypeObject }
+
+ const typeFromObject = parseValueTypeObject(typeObject as ValueTypeObjectPayload)
+ const typeFromDefaultValue = parseValueTypeDefault(typeDefinition as ValueTypeDefault)
+ const typeFromConstant = parseValueTypeConstant(typeDefinition as ValueTypeConstant)
const type = typeFromObject || typeFromDefaultValue || typeFromConstant
if (type) return type
- const propertyPath = payload.controller ? `${payload.controller}.${payload.typeDefinition}` : payload.token
+ const propertyPath = controller ? `${controller}.${typeDefinition}` : token
- throw new Error(`Unknown value type "${propertyPath}" for "${payload.token}" value`)
+ throw new Error(`Unknown value type "${propertyPath}" for "${token}" value`)
}
-function defaultValueForDefinition(typeDefinition: ValueTypeDefinition): ValueTypeDefault {
+export function defaultValueForDefinition(typeDefinition: ValueTypeDefinition): ValueTypeDefault {
const constant = parseValueTypeConstant(typeDefinition as ValueTypeConstant)
-
if (constant) return defaultValuesByType[constant]
- const defaultValue = (typeDefinition as ValueTypeObject).default
- if (defaultValue !== undefined) return defaultValue
+ const hasDefault = hasProperty(typeDefinition, "default")
+ const hasType = hasProperty(typeDefinition, "type")
+ const typeObject = typeDefinition as ValueTypeObject
+
+ if (hasDefault) return typeObject.default!
+
+ if (hasType) {
+ const { type } = typeObject
+ const constantFromType = parseValueTypeConstant(type)
+
+ if (constantFromType) return defaultValuesByType[constantFromType]
+ }
return typeDefinition
}
-function valueDescriptorForTokenAndTypeDefinition(payload: {
- token: string
- typeDefinition: ValueTypeDefinition
- controller?: string
-}) {
- const key = `${dasherize(payload.token)}-value`
+function valueDescriptorForTokenAndTypeDefinition(payload: ValueTypeDefinitionPayload) {
+ const { token, typeDefinition } = payload
+
+ const key = `${dasherize(token)}-value`
const type = parseValueTypeDefinition(payload)
return {
type,
key,
name: camelize(key),
get defaultValue() {
- return defaultValueForDefinition(payload.typeDefinition)
+ return defaultValueForDefinition(typeDefinition)
},
get hasCustomDefaultValue() {
- return parseValueTypeDefault(payload.typeDefinition) !== undefined
+ return parseValueTypeDefault(typeDefinition) !== undefined
},
reader: readers[type],
writer: writers[type] || writers.default,
@@ -223,7 +248,7 @@ const readers: { [type: string]: Reader } = {
},
number(value: string): number {
- return Number(value)
+ return Number(value.replace(/_/g, ""))
},
object(value: string): object {
diff --git a/src/mutation-observers/element_observer.ts b/src/mutation-observers/element_observer.ts
index 2902cd00..544de6e4 100644
--- a/src/mutation-observers/element_observer.ts
+++ b/src/mutation-observers/element_observer.ts
@@ -14,7 +14,7 @@ export class ElementObserver {
private elements: Set
private mutationObserver: MutationObserver
- private mutationObserverInit = { attributes: true, childList: true, subtree: true }
+ private mutationObserverInit: MutationObserverInit = { attributes: true, childList: true, subtree: true }
constructor(element: Element, delegate: ElementObserverDelegate) {
this.element = element
@@ -83,15 +83,14 @@ export class ElementObserver {
private processMutation(mutation: MutationRecord) {
if (mutation.type == "attributes") {
- this.processAttributeChange(mutation.target, mutation.attributeName!)
+ this.processAttributeChange(mutation.target as Element, mutation.attributeName!)
} else if (mutation.type == "childList") {
this.processRemovedNodes(mutation.removedNodes)
this.processAddedNodes(mutation.addedNodes)
}
}
- private processAttributeChange(node: Node, attributeName: string) {
- const element = node as Element
+ private processAttributeChange(element: Element, attributeName: string) {
if (this.elements.has(element)) {
if (this.delegate.elementAttributeChanged && this.matchElement(element)) {
this.delegate.elementAttributeChanged(element, attributeName)
diff --git a/src/mutation-observers/selector_observer.ts b/src/mutation-observers/selector_observer.ts
index d18d09ec..6321de64 100644
--- a/src/mutation-observers/selector_observer.ts
+++ b/src/mutation-observers/selector_observer.ts
@@ -8,14 +8,14 @@ export interface SelectorObserverDelegate {
}
export class SelectorObserver implements ElementObserverDelegate {
- private selector: string
- private elementObserver: ElementObserver
- private delegate: SelectorObserverDelegate
- private matchesByElement: Multimap
- private details: object
-
- constructor(element: Element, selector: string, delegate: SelectorObserverDelegate, details: object = {}) {
- this.selector = selector
+ private readonly elementObserver: ElementObserver
+ private readonly delegate: SelectorObserverDelegate
+ private readonly matchesByElement: Multimap
+ private readonly details: object
+ _selector: string | null
+
+ constructor(element: Element, selector: string, delegate: SelectorObserverDelegate, details: object) {
+ this._selector = selector
this.details = details
this.elementObserver = new ElementObserver(element, this)
this.delegate = delegate
@@ -26,6 +26,15 @@ export class SelectorObserver implements ElementObserverDelegate {
return this.elementObserver.started
}
+ get selector() {
+ return this._selector
+ }
+
+ set selector(selector: string | null) {
+ this._selector = selector
+ this.refresh()
+ }
+
start() {
this.elementObserver.start()
}
@@ -49,47 +58,73 @@ export class SelectorObserver implements ElementObserverDelegate {
// Element observer delegate
matchElement(element: Element): boolean {
- const matches = element.matches(this.selector)
+ const { selector } = this
- if (this.delegate.selectorMatchElement) {
- return matches && this.delegate.selectorMatchElement(element, this.details)
- }
+ if (selector) {
+ const matches = element.matches(selector)
+
+ if (this.delegate.selectorMatchElement) {
+ return matches && this.delegate.selectorMatchElement(element, this.details)
+ }
- return matches
+ return matches
+ } else {
+ return false
+ }
}
matchElementsInTree(tree: Element): Element[] {
- const match = this.matchElement(tree) ? [tree] : []
- const matches = Array.from(tree.querySelectorAll(this.selector)).filter((match) => this.matchElement(match))
- return match.concat(matches)
+ const { selector } = this
+
+ if (selector) {
+ const match = this.matchElement(tree) ? [tree] : []
+ const matches = Array.from(tree.querySelectorAll(selector)).filter((match) => this.matchElement(match))
+ return match.concat(matches)
+ } else {
+ return []
+ }
}
elementMatched(element: Element) {
- this.selectorMatched(element)
+ const { selector } = this
+
+ if (selector) {
+ this.selectorMatched(element, selector)
+ }
}
elementUnmatched(element: Element) {
- this.selectorUnmatched(element)
+ const selectors = this.matchesByElement.getKeysForValue(element)
+
+ for (const selector of selectors) {
+ this.selectorUnmatched(element, selector)
+ }
}
elementAttributeChanged(element: Element, _attributeName: string) {
- const matches = this.matchElement(element)
- const matchedBefore = this.matchesByElement.has(this.selector, element)
+ const { selector } = this
- if (!matches && matchedBefore) {
- this.selectorUnmatched(element)
+ if (selector) {
+ const matches = this.matchElement(element)
+ const matchedBefore = this.matchesByElement.has(selector, element)
+
+ if (matches && !matchedBefore) {
+ this.selectorMatched(element, selector)
+ } else if (!matches && matchedBefore) {
+ this.selectorUnmatched(element, selector)
+ }
}
}
- private selectorMatched(element: Element) {
- if (this.delegate.selectorMatched) {
- this.delegate.selectorMatched(element, this.selector, this.details)
- this.matchesByElement.add(this.selector, element)
- }
+ // Selector management
+
+ private selectorMatched(element: Element, selector: string) {
+ this.delegate.selectorMatched(element, selector, this.details)
+ this.matchesByElement.add(selector, element)
}
- private selectorUnmatched(element: Element) {
- this.delegate.selectorUnmatched(element, this.selector, this.details)
- this.matchesByElement.delete(this.selector, element)
+ private selectorUnmatched(element: Element, selector: string) {
+ this.delegate.selectorUnmatched(element, selector, this.details)
+ this.matchesByElement.delete(selector, element)
}
}
diff --git a/src/tests/cases/dom_test_case.ts b/src/tests/cases/dom_test_case.ts
index 438239ef..fe39ac39 100644
--- a/src/tests/cases/dom_test_case.ts
+++ b/src/tests/cases/dom_test_case.ts
@@ -51,6 +51,15 @@ export class DOMTestCase extends TestCase {
return event
}
+ async triggerMouseEvent(selectorOrTarget: string | EventTarget, type: string, options: MouseEventInit = {}) {
+ const eventTarget = typeof selectorOrTarget == "string" ? this.findElement(selectorOrTarget) : selectorOrTarget
+ const event = new MouseEvent(type, options)
+
+ eventTarget.dispatchEvent(event)
+ await this.nextFrame
+ return event
+ }
+
async triggerKeyboardEvent(selectorOrTarget: string | EventTarget, type: string, options: KeyboardEventInit = {}) {
const eventTarget = typeof selectorOrTarget == "string" ? this.findElement(selectorOrTarget) : selectorOrTarget
const event = new KeyboardEvent(type, options)
@@ -60,6 +69,34 @@ export class DOMTestCase extends TestCase {
return event
}
+ async setAttribute(selectorOrElement: string | Element, name: string, value: string) {
+ const element = typeof selectorOrElement == "string" ? this.findElement(selectorOrElement) : selectorOrElement
+
+ element.setAttribute(name, value)
+ await this.nextFrame
+ }
+
+ async removeAttribute(selectorOrElement: string | Element, name: string) {
+ const element = typeof selectorOrElement == "string" ? this.findElement(selectorOrElement) : selectorOrElement
+
+ element.removeAttribute(name)
+ await this.nextFrame
+ }
+
+ async appendChild(selectorOrElement: T | string, child: T) {
+ const parent = typeof selectorOrElement == "string" ? this.findElement(selectorOrElement) : selectorOrElement
+
+ parent.appendChild(child)
+ await this.nextFrame
+ }
+
+ async remove(selectorOrElement: Element | string) {
+ const element = typeof selectorOrElement == "string" ? this.findElement(selectorOrElement) : selectorOrElement
+
+ element.remove()
+ await this.nextFrame
+ }
+
findElement(selector: string) {
const element = this.fixtureElement.querySelector(selector)
if (element) {
diff --git a/src/tests/controllers/outlet_controller.ts b/src/tests/controllers/outlet_controller.ts
index c3a5b840..b382f80c 100644
--- a/src/tests/controllers/outlet_controller.ts
+++ b/src/tests/controllers/outlet_controller.ts
@@ -19,6 +19,9 @@ export class OutletController extends BaseOutletController {
alphaOutletDisconnectedCallCount: Number,
betaOutletConnectedCallCount: Number,
betaOutletDisconnectedCallCount: Number,
+ betaOutletsInConnect: Number,
+ gammaOutletConnectedCallCount: Number,
+ gammaOutletDisconnectedCallCount: Number,
namespacedEpsilonOutletConnectedCallCount: Number,
namespacedEpsilonOutletDisconnectedCallCount: Number,
}
@@ -44,9 +47,16 @@ export class OutletController extends BaseOutletController {
alphaOutletDisconnectedCallCountValue = 0
betaOutletConnectedCallCountValue = 0
betaOutletDisconnectedCallCountValue = 0
+ betaOutletsInConnectValue = 0
+ gammaOutletConnectedCallCountValue = 0
+ gammaOutletDisconnectedCallCountValue = 0
namespacedEpsilonOutletConnectedCallCountValue = 0
namespacedEpsilonOutletDisconnectedCallCountValue = 0
+ connect() {
+ this.betaOutletsInConnectValue = this.betaOutlets.length
+ }
+
alphaOutletConnected(_outlet: Controller, element: Element) {
if (this.hasConnectedClass) element.classList.add(this.connectedClass)
this.alphaOutletConnectedCallCountValue++
@@ -67,6 +77,11 @@ export class OutletController extends BaseOutletController {
this.betaOutletDisconnectedCallCountValue++
}
+ gammaOutletConnected(_outlet: Controller, element: Element) {
+ if (this.hasConnectedClass) element.classList.add(this.connectedClass)
+ this.gammaOutletConnectedCallCountValue++
+ }
+
namespacedEpsilonOutletConnected(_outlet: Controller, element: Element) {
if (this.hasConnectedClass) element.classList.add(this.connectedClass)
this.namespacedEpsilonOutletConnectedCallCountValue++
diff --git a/src/tests/modules/core/action_click_filter_tests.ts b/src/tests/modules/core/action_click_filter_tests.ts
new file mode 100644
index 00000000..accec9ac
--- /dev/null
+++ b/src/tests/modules/core/action_click_filter_tests.ts
@@ -0,0 +1,21 @@
+import { LogControllerTestCase } from "../../cases/log_controller_test_case"
+
+export default class ActionClickFilterTests extends LogControllerTestCase {
+ identifier = ["a"]
+
+ fixtureHTML = `
+
+
+
+ `
+
+ async "test ignoring clicks with unmatched modifier"() {
+ const button = this.findElement("#ctrl")
+ await this.triggerMouseEvent(button, "click", { ctrlKey: true })
+ await this.nextFrame
+ this.assertActions(
+ { name: "log", identifier: "a", eventType: "click", currentTarget: button },
+ { name: "log2", identifier: "a", eventType: "click", currentTarget: button }
+ )
+ }
+}
diff --git a/src/tests/modules/core/event_options_tests.ts b/src/tests/modules/core/event_options_tests.ts
index 403cb10a..45027cd3 100644
--- a/src/tests/modules/core/event_options_tests.ts
+++ b/src/tests/modules/core/event_options_tests.ts
@@ -1,3 +1,4 @@
+import type { Controller } from "src/core"
import { LogControllerTestCase } from "../../cases/log_controller_test_case"
export default class EventOptionsTests extends LogControllerTestCase {
@@ -177,6 +178,47 @@ export default class EventOptionsTests extends LogControllerTestCase {
this.assertNoActions()
}
+ async "test custom action option callback params contain the controller instance"() {
+ let lastActionOptions: { controller?: Controller } = {}
+
+ const mockCallback = (options: Object) => {
+ lastActionOptions = options
+ }
+
+ this.application.registerActionOption("all", (options: Object) => {
+ mockCallback(options)
+ return true
+ })
+
+ await this.setAction(this.buttonElement, "click->c#log:all")
+
+ await this.triggerEvent(this.buttonElement, "click")
+
+ this.assertActions({ name: "log", identifier: "c", eventType: "click", currentTarget: this.buttonElement })
+
+ this.assert.deepEqual(["name", "value", "event", "element", "controller"], Object.keys(lastActionOptions))
+
+ this.assert.equal(
+ lastActionOptions.controller,
+ this.application.getControllerForElementAndIdentifier(this.element, "c")
+ )
+
+ this.controllerConstructor.actionLog = [] // clear actions
+
+ await this.setAction(this.buttonElement, "click->d#log:all")
+
+ await this.triggerEvent(this.buttonElement, "click")
+
+ this.assertActions({ name: "log", identifier: "d", eventType: "click", currentTarget: this.buttonElement })
+
+ this.assert.deepEqual(["name", "value", "event", "element", "controller"], Object.keys(lastActionOptions))
+
+ this.assert.equal(
+ lastActionOptions.controller,
+ this.application.getControllerForElementAndIdentifier(this.element, "d")
+ )
+ }
+
async "test custom option"() {
this.application.registerActionOption("open", ({ value, event: { type, target } }) => {
switch (type) {
@@ -213,6 +255,43 @@ export default class EventOptionsTests extends LogControllerTestCase {
this.assertActions({ name: "log", eventType: "toggle" })
}
+ async "test custom action option callback event contains params"() {
+ let lastActionEventParams: Object = {}
+
+ // clone the params to ensure we check the value as the callback receives it
+ // not the event after all actions have resolved
+
+ const mockCallback = ({ event: { params = {} } = {} }) => {
+ lastActionEventParams = { ...params }
+ }
+
+ this.application.registerActionOption("all", (options: Object) => {
+ mockCallback(options)
+ return true
+ })
+
+ this.buttonElement.setAttribute("data-c-custom-number-param", "41")
+ this.buttonElement.setAttribute("data-c-custom-string-param", "validation")
+ this.buttonElement.setAttribute("data-c-custom-boolean-param", "true")
+ this.buttonElement.setAttribute("data-d-should-ignore-param", "_IGNORED_")
+
+ await this.setAction(this.buttonElement, "click->c#log:all")
+
+ await this.triggerEvent(this.buttonElement, "click")
+
+ this.assertActions({ name: "log", identifier: "c", eventType: "click", currentTarget: this.buttonElement })
+
+ const expectedEventParams = {
+ customBoolean: true,
+ customNumber: 41,
+ customString: "validation",
+ }
+
+ this.assert.deepEqual(this.controllerConstructor.actionLog[0].params, expectedEventParams)
+
+ this.assert.deepEqual(lastActionEventParams, expectedEventParams)
+ }
+
setAction(element: Element, value: string) {
element.setAttribute("data-action", value)
return this.nextFrame
diff --git a/src/tests/modules/core/loading_tests.ts b/src/tests/modules/core/loading_tests.ts
index 1190dcdb..20ed5c92 100644
--- a/src/tests/modules/core/loading_tests.ts
+++ b/src/tests/modules/core/loading_tests.ts
@@ -13,12 +13,20 @@ class LoadableController extends LogController {
}
class AfterLoadController extends LogController {
+ static values = {
+ example: { default: "demo", type: String },
+ }
+
static afterLoad(identifier: string, application: any) {
const newElement = document.createElement("div")
newElement.classList.add("after-load-test")
newElement.setAttribute(application.schema.controllerAttribute, identifier)
application.element.append(newElement)
- document.dispatchEvent(new CustomEvent("test", { detail: { identifier, application } }))
+ document.dispatchEvent(
+ new CustomEvent("test", {
+ detail: { identifier, application, exampleDefault: this.values.example.default, controller: this },
+ })
+ )
}
}
@@ -37,13 +45,15 @@ export default class ApplicationTests extends ApplicationTestCase {
"test module with afterLoad method should be triggered when registered"() {
// set up an event listener to track the params passed into the AfterLoadController
- let data: { application?: any; identifier?: string } = {}
+ let data: { application?: any; identifier?: string; exampleDefault?: string; controller?: any } = {}
document.addEventListener("test", (({ detail }: CustomEvent) => {
data = detail
}) as EventListener)
- this.assert.equal(data.identifier, undefined)
this.assert.equal(data.application, undefined)
+ this.assert.equal(data.controller, undefined)
+ this.assert.equal(data.exampleDefault, undefined)
+ this.assert.equal(data.identifier, undefined)
this.application.register("after-load", AfterLoadController)
@@ -51,8 +61,10 @@ export default class ApplicationTests extends ApplicationTestCase {
this.assert.equal(this.findElements('[data-controller="after-load"]').length, 1)
// check that static method was correctly called with the params
- this.assert.equal(data.identifier, "after-load")
this.assert.equal(data.application, this.application)
+ this.assert.equal(data.controller, AfterLoadController)
+ this.assert.equal(data.exampleDefault, "demo")
+ this.assert.equal(data.identifier, "after-load")
}
get controllers() {
diff --git a/src/tests/modules/core/outlet_order_tests.ts b/src/tests/modules/core/outlet_order_tests.ts
new file mode 100644
index 00000000..5d8bfcf4
--- /dev/null
+++ b/src/tests/modules/core/outlet_order_tests.ts
@@ -0,0 +1,45 @@
+import { ControllerTestCase } from "../../cases/controller_test_case"
+import { OutletController } from "../../controllers/outlet_controller"
+
+const connectOrder: string[] = []
+
+class OutletOrderController extends OutletController {
+ connect() {
+ connectOrder.push(`${this.identifier}-${this.element.id}-start`)
+ super.connect()
+ connectOrder.push(`${this.identifier}-${this.element.id}-end`)
+ }
+}
+
+export default class OutletOrderTests extends ControllerTestCase(OutletOrderController) {
+ fixtureHTML = `
+ Search
+ Beta
+ Beta
+ Beta
+ `
+
+ get identifiers() {
+ return ["alpha", "beta"]
+ }
+
+ async "test can access outlets in connect() even if they are referenced before they are connected"() {
+ this.assert.equal(this.controller.betaOutletsInConnectValue, 3)
+
+ this.controller.betaOutlets.forEach((outlet) => {
+ this.assert.equal(outlet.identifier, "beta")
+ this.assert.equal(Array.from(outlet.element.classList.values()), "beta")
+ })
+
+ this.assert.deepEqual(connectOrder, [
+ "alpha-alpha1-start",
+ "beta-beta-1-start",
+ "beta-beta-1-end",
+ "beta-beta-2-start",
+ "beta-beta-2-end",
+ "beta-beta-3-start",
+ "beta-beta-3-end",
+ "alpha-alpha1-end",
+ ])
+ }
+}
diff --git a/src/tests/modules/core/outlet_tests.ts b/src/tests/modules/core/outlet_tests.ts
index 0ff686d8..fb87ba12 100644
--- a/src/tests/modules/core/outlet_tests.ts
+++ b/src/tests/modules/core/outlet_tests.ts
@@ -132,7 +132,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
this.assert.throws(() => this.controller.alphaOutletElement)
}
- "test outlet connected callback fires"() {
+ async "test outlet connected callback fires"() {
const alphaOutlets = this.controller.alphaOutletElements.filter((outlet) => outlet.classList.contains("connected"))
this.assert.equal(alphaOutlets.length, 2)
@@ -149,13 +149,12 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
async "test outlet connected callback when element is inserted"() {
const betaOutletElement = document.createElement("div")
- betaOutletElement.setAttribute("class", "beta")
- betaOutletElement.setAttribute("data-controller", "beta")
+ await this.setAttribute(betaOutletElement, "class", "beta")
+ await this.setAttribute(betaOutletElement, "data-controller", "beta")
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 2)
- this.controller.element.appendChild(betaOutletElement)
- await this.nextFrame
+ await this.appendChild(this.controller.element, betaOutletElement)
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 3)
this.assert.ok(
@@ -164,8 +163,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
)
this.assert.ok(betaOutletElement.isConnected, "element is present in document")
- this.findElement("#container").appendChild(betaOutletElement.cloneNode(true))
- await this.nextFrame
+ await this.appendChild("#container", betaOutletElement.cloneNode(true))
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 4)
}
@@ -175,9 +173,8 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 2)
- element.setAttribute("data-controller", "beta")
- element.classList.add("beta")
- await this.nextFrame
+ await this.setAttribute(element, "data-controller", "beta")
+ await this.setAttribute(element, "class", "beta")
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 3)
this.assert.ok(element.classList.contains("connected"), `expected "${element.className}" to contain "connected"`)
@@ -189,8 +186,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 2)
- element.classList.add("beta")
- await this.nextFrame
+ await this.setAttribute(element, "class", "beta")
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 3)
this.assert.ok(element.classList.contains("connected"), `expected "${element.className}" to contain "connected"`)
@@ -202,8 +198,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 2)
- element.setAttribute(`data-controller`, "beta")
- await this.nextFrame
+ await this.setAttribute(element, "data-controller", "beta")
this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 3)
this.assert.ok(element.classList.contains("connected"), `expected "${element.className}" to contain "connected"`)
@@ -236,8 +231,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
`expected "${disconnectedAlpha.className}" not to contain "disconnected"`
)
- disconnectedAlpha.parentElement?.removeChild(disconnectedAlpha)
- await this.nextFrame
+ await this.remove(disconnectedAlpha)
this.assert.equal(this.controller.alphaOutletDisconnectedCallCountValue, 1)
this.assert.ok(
@@ -256,8 +250,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
`expected "${disconnectedEpsilon.className}" not to contain "disconnected"`
)
- disconnectedEpsilon.parentElement?.removeChild(disconnectedEpsilon)
- await this.nextFrame
+ await this.remove(disconnectedEpsilon)
this.assert.equal(this.controller.namespacedEpsilonOutletDisconnectedCallCountValue, 1)
this.assert.ok(
@@ -276,8 +269,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
`expected "${element.className}" not to contain "disconnected"`
)
- element.removeAttribute(`id`)
- await this.nextFrame
+ await this.removeAttribute(element, "id")
this.assert.equal(this.controller.alphaOutletDisconnectedCallCountValue, 1)
this.assert.ok(
@@ -296,8 +288,7 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
`expected "${element.className}" not to contain "disconnected"`
)
- element.removeAttribute(`data-controller`)
- await this.nextFrame
+ await this.removeAttribute(element, "data-controller")
this.assert.equal(this.controller.alphaOutletDisconnectedCallCountValue, 1)
this.assert.ok(
@@ -306,4 +297,73 @@ export default class OutletTests extends ControllerTestCase(OutletController) {
)
this.assert.ok(element.isConnected, "element is still present in document")
}
+
+ async "test outlet connect callback when the controlled element's outlet attribute is added"() {
+ const gamma2 = this.findElement("#gamma2")
+
+ await this.setAttribute(this.controller.element, `data-${this.identifier}-gamma-outlet`, "#gamma2")
+
+ this.assert.equal(this.controller.gammaOutletConnectedCallCountValue, 1)
+ this.assert.ok(gamma2.isConnected, "#gamma2 is still present in document")
+ this.assert.ok(gamma2.classList.contains("connected"), `expected "${gamma2.className}" to contain "connected"`)
+ }
+
+ async "test outlet connect callback doesn't get trigged when any attribute gets added to the controller element"() {
+ this.assert.equal(this.controller.alphaOutletConnectedCallCountValue, 2)
+ this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 2)
+ this.assert.equal(this.controller.gammaOutletConnectedCallCountValue, 0)
+ this.assert.equal(this.controller.namespacedEpsilonOutletConnectedCallCountValue, 2)
+
+ await this.setAttribute(this.controller.element, "data-some-random-attribute", "#alpha1")
+
+ this.assert.equal(this.controller.alphaOutletConnectedCallCountValue, 2)
+ this.assert.equal(this.controller.betaOutletConnectedCallCountValue, 2)
+ this.assert.equal(this.controller.gammaOutletConnectedCallCountValue, 0)
+ this.assert.equal(this.controller.namespacedEpsilonOutletConnectedCallCountValue, 2)
+
+ this.assert.equal(this.controller.alphaOutletDisconnectedCallCountValue, 0)
+ this.assert.equal(this.controller.betaOutletDisconnectedCallCountValue, 0)
+ this.assert.equal(this.controller.gammaOutletDisconnectedCallCountValue, 0)
+ this.assert.equal(this.controller.namespacedEpsilonOutletDisconnectedCallCountValue, 0)
+ }
+
+ async "test outlet connect callback when the controlled element's outlet attribute is changed"() {
+ const alpha1 = this.findElement("#alpha1")
+ const alpha2 = this.findElement("#alpha2")
+
+ await this.setAttribute(this.controller.element, `data-${this.identifier}-alpha-outlet`, "#alpha1")
+
+ this.assert.equal(this.controller.alphaOutletConnectedCallCountValue, 2)
+ this.assert.equal(this.controller.alphaOutletDisconnectedCallCountValue, 1)
+ this.assert.ok(alpha1.isConnected, "alpha1 is still present in document")
+ this.assert.ok(alpha2.isConnected, "alpha2 is still present in document")
+ this.assert.ok(alpha1.classList.contains("connected"), `expected "${alpha1.className}" to contain "connected"`)
+ this.assert.notOk(
+ alpha1.classList.contains("disconnected"),
+ `expected "${alpha1.className}" to contain "disconnected"`
+ )
+ this.assert.ok(
+ alpha2.classList.contains("disconnected"),
+ `expected "${alpha2.className}" to contain "disconnected"`
+ )
+ }
+
+ async "test outlet disconnected callback when the controlled element's outlet attribute is removed"() {
+ const alpha1 = this.findElement("#alpha1")
+ const alpha2 = this.findElement("#alpha2")
+
+ await this.removeAttribute(this.controller.element, `data-${this.identifier}-alpha-outlet`)
+
+ this.assert.equal(this.controller.alphaOutletDisconnectedCallCountValue, 2)
+ this.assert.ok(alpha1.isConnected, "#alpha1 is still present in document")
+ this.assert.ok(alpha2.isConnected, "#alpha2 is still present in document")
+ this.assert.ok(
+ alpha1.classList.contains("disconnected"),
+ `expected "${alpha1.className}" to contain "disconnected"`
+ )
+ this.assert.ok(
+ alpha2.classList.contains("disconnected"),
+ `expected "${alpha2.className}" to contain "disconnected"`
+ )
+ }
}
diff --git a/src/tests/modules/core/value_properties_tests.ts b/src/tests/modules/core/value_properties_tests.ts
new file mode 100644
index 00000000..0c8a583d
--- /dev/null
+++ b/src/tests/modules/core/value_properties_tests.ts
@@ -0,0 +1,176 @@
+import { ValueController } from "../../controllers/value_controller"
+import { ControllerTestCase } from "../../cases/controller_test_case"
+
+import {
+ parseValueTypeDefault,
+ parseValueTypeConstant,
+ parseValueTypeObject,
+ parseValueTypeDefinition,
+ defaultValueForDefinition,
+} from "../../../core/value_properties"
+
+export default class ValuePropertiesTests extends ControllerTestCase(ValueController) {
+ "test parseValueTypeConstant"() {
+ this.assert.equal(parseValueTypeConstant(String), "string")
+ this.assert.equal(parseValueTypeConstant(Boolean), "boolean")
+ this.assert.equal(parseValueTypeConstant(Array), "array")
+ this.assert.equal(parseValueTypeConstant(Object), "object")
+ this.assert.equal(parseValueTypeConstant(Number), "number")
+
+ this.assert.equal(parseValueTypeConstant("" as any), undefined)
+ this.assert.equal(parseValueTypeConstant({} as any), undefined)
+ this.assert.equal(parseValueTypeConstant([] as any), undefined)
+ this.assert.equal(parseValueTypeConstant(true as any), undefined)
+ this.assert.equal(parseValueTypeConstant(false as any), undefined)
+ this.assert.equal(parseValueTypeConstant(0 as any), undefined)
+ this.assert.equal(parseValueTypeConstant(1 as any), undefined)
+ this.assert.equal(parseValueTypeConstant(null!), undefined)
+ this.assert.equal(parseValueTypeConstant(undefined), undefined)
+ }
+
+ "test parseValueTypeDefault"() {
+ this.assert.equal(parseValueTypeDefault(""), "string")
+ this.assert.equal(parseValueTypeDefault("Some string"), "string")
+
+ this.assert.equal(parseValueTypeDefault(true), "boolean")
+ this.assert.equal(parseValueTypeDefault(false), "boolean")
+
+ this.assert.equal(parseValueTypeDefault([]), "array")
+ this.assert.equal(parseValueTypeDefault([1, 2, 3]), "array")
+ this.assert.equal(parseValueTypeDefault([true, false, true]), "array")
+ this.assert.equal(parseValueTypeDefault([{}, {}, {}]), "array")
+
+ this.assert.equal(parseValueTypeDefault({}), "object")
+ this.assert.equal(parseValueTypeDefault({ one: "key" }), "object")
+
+ this.assert.equal(parseValueTypeDefault(-1), "number")
+ this.assert.equal(parseValueTypeDefault(0), "number")
+ this.assert.equal(parseValueTypeDefault(1), "number")
+ this.assert.equal(parseValueTypeDefault(-0.1), "number")
+ this.assert.equal(parseValueTypeDefault(0.0), "number")
+ this.assert.equal(parseValueTypeDefault(0.1), "number")
+
+ this.assert.equal(parseValueTypeDefault(null!), undefined)
+ this.assert.equal(parseValueTypeDefault(undefined!), undefined)
+ }
+
+ "test parseValueTypeObject"() {
+ const typeObject = (object: any) => {
+ return parseValueTypeObject({
+ controller: this.controller.identifier,
+ token: "url",
+ typeObject: object,
+ })
+ }
+
+ this.assert.equal(typeObject({ type: String, default: "" }), "string")
+ this.assert.equal(typeObject({ type: String, default: "123" }), "string")
+ this.assert.equal(typeObject({ type: String }), "string")
+ this.assert.equal(typeObject({ default: "" }), "string")
+ this.assert.equal(typeObject({ default: "123" }), "string")
+
+ this.assert.equal(typeObject({ type: Number, default: 0 }), "number")
+ this.assert.equal(typeObject({ type: Number, default: 1 }), "number")
+ this.assert.equal(typeObject({ type: Number, default: -1 }), "number")
+ this.assert.equal(typeObject({ type: Number }), "number")
+ this.assert.equal(typeObject({ default: 0 }), "number")
+ this.assert.equal(typeObject({ default: 1 }), "number")
+ this.assert.equal(typeObject({ default: -1 }), "number")
+
+ this.assert.equal(typeObject({ type: Array, default: [] }), "array")
+ this.assert.equal(typeObject({ type: Array, default: [1] }), "array")
+ this.assert.equal(typeObject({ type: Array }), "array")
+ this.assert.equal(typeObject({ default: [] }), "array")
+ this.assert.equal(typeObject({ default: [1] }), "array")
+
+ this.assert.equal(typeObject({ type: Object, default: {} }), "object")
+ this.assert.equal(typeObject({ type: Object, default: { some: "key" } }), "object")
+ this.assert.equal(typeObject({ type: Object }), "object")
+ this.assert.equal(typeObject({ default: {} }), "object")
+ this.assert.equal(typeObject({ default: { some: "key" } }), "object")
+
+ this.assert.equal(typeObject({ type: Boolean, default: true }), "boolean")
+ this.assert.equal(typeObject({ type: Boolean, default: false }), "boolean")
+ this.assert.equal(typeObject({ type: Boolean }), "boolean")
+ this.assert.equal(typeObject({ default: false }), "boolean")
+
+ this.assert.throws(() => typeObject({ type: Boolean, default: "something else" }), {
+ name: "Error",
+ message: `The specified default value for the Stimulus Value "test.url" must match the defined type "boolean". The provided default value of "something else" is of type "string".`,
+ })
+
+ this.assert.throws(() => typeObject({ type: Boolean, default: "true" }), {
+ name: "Error",
+ message: `The specified default value for the Stimulus Value "test.url" must match the defined type "boolean". The provided default value of "true" is of type "string".`,
+ })
+ }
+
+ "test parseValueTypeDefinition booleans"() {
+ const typeDefinition = (definition: any) => {
+ return parseValueTypeDefinition({
+ controller: this.controller.identifier,
+ token: "url",
+ typeDefinition: definition,
+ })
+ }
+
+ this.assert.equal(typeDefinition(Boolean), "boolean")
+ this.assert.equal(typeDefinition(true), "boolean")
+ this.assert.equal(typeDefinition(false), "boolean")
+ this.assert.equal(typeDefinition({ type: Boolean, default: false }), "boolean")
+ this.assert.equal(typeDefinition({ type: Boolean }), "boolean")
+ this.assert.equal(typeDefinition({ default: true }), "boolean")
+
+ // since the provided value is actually an object, it's going to be of type "object"
+ this.assert.equal(typeDefinition({ default: null }), "object")
+ this.assert.equal(typeDefinition({ default: undefined }), "object")
+
+ this.assert.equal(typeDefinition({}), "object")
+ this.assert.equal(typeDefinition(""), "string")
+ this.assert.equal(typeDefinition([]), "array")
+
+ this.assert.throws(() => typeDefinition(null))
+ this.assert.throws(() => typeDefinition(undefined))
+ }
+
+ "test defaultValueForDefinition"() {
+ this.assert.deepEqual(defaultValueForDefinition(String), "")
+ this.assert.deepEqual(defaultValueForDefinition(Boolean), false)
+ this.assert.deepEqual(defaultValueForDefinition(Object), {})
+ this.assert.deepEqual(defaultValueForDefinition(Array), [])
+ this.assert.deepEqual(defaultValueForDefinition(Number), 0)
+
+ this.assert.deepEqual(defaultValueForDefinition({ type: String }), "")
+ this.assert.deepEqual(defaultValueForDefinition({ type: Boolean }), false)
+ this.assert.deepEqual(defaultValueForDefinition({ type: Object }), {})
+ this.assert.deepEqual(defaultValueForDefinition({ type: Array }), [])
+ this.assert.deepEqual(defaultValueForDefinition({ type: Number }), 0)
+
+ this.assert.deepEqual(defaultValueForDefinition({ type: String, default: null }), null)
+ this.assert.deepEqual(defaultValueForDefinition({ type: Boolean, default: null }), null)
+ this.assert.deepEqual(defaultValueForDefinition({ type: Object, default: null }), null)
+ this.assert.deepEqual(defaultValueForDefinition({ type: Array, default: null }), null)
+ this.assert.deepEqual(defaultValueForDefinition({ type: Number, default: null }), null)
+
+ this.assert.deepEqual(defaultValueForDefinition({ type: String, default: "some string" }), "some string")
+ this.assert.deepEqual(defaultValueForDefinition({ type: Boolean, default: true }), true)
+ this.assert.deepEqual(defaultValueForDefinition({ type: Object, default: { some: "key" } }), { some: "key" })
+ this.assert.deepEqual(defaultValueForDefinition({ type: Array, default: [1, 2, 3] }), [1, 2, 3])
+ this.assert.deepEqual(defaultValueForDefinition({ type: Number, default: 99 }), 99)
+
+ this.assert.deepEqual(defaultValueForDefinition("some string"), "some string")
+ this.assert.deepEqual(defaultValueForDefinition(true), true)
+ this.assert.deepEqual(defaultValueForDefinition({ some: "key" }), { some: "key" })
+ this.assert.deepEqual(defaultValueForDefinition([1, 2, 3]), [1, 2, 3])
+ this.assert.deepEqual(defaultValueForDefinition(99), 99)
+
+ this.assert.deepEqual(defaultValueForDefinition({ default: "some string" }), "some string")
+ this.assert.deepEqual(defaultValueForDefinition({ default: true }), true)
+ this.assert.deepEqual(defaultValueForDefinition({ default: { some: "key" } }), { some: "key" })
+ this.assert.deepEqual(defaultValueForDefinition({ default: [1, 2, 3] }), [1, 2, 3])
+ this.assert.deepEqual(defaultValueForDefinition({ default: 99 }), 99)
+
+ this.assert.deepEqual(defaultValueForDefinition({ default: null }), null)
+ this.assert.deepEqual(defaultValueForDefinition({ default: undefined }), undefined)
+ }
+}
diff --git a/src/tests/modules/core/value_tests.ts b/src/tests/modules/core/value_tests.ts
index 1bcb0377..fd60ee1a 100644
--- a/src/tests/modules/core/value_tests.ts
+++ b/src/tests/modules/core/value_tests.ts
@@ -46,6 +46,14 @@ export default class ValueTests extends ControllerTestCase(ValueController) {
this.controller.numericValue = "" as any
this.assert.equal(this.controller.numericValue, 0)
this.assert.equal(this.get("numeric-value"), "")
+
+ // Number values should support Numeric separators
+ this.set("numeric-value", "7_150")
+ this.assert.equal(this.controller.numericValue, 7150)
+
+ // Number values should be written simply, without Numeric separators
+ this.controller.numericValue = 10500
+ this.assert.deepEqual(this.get("numeric-value"), "10500")
}
"test boolean values"() {
diff --git a/yarn.lock b/yarn.lock
index a54c7735..547fd21f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -28,34 +28,46 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
-"@eslint/eslintrc@^1.3.2":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.2.tgz#58b69582f3b7271d8fa67fe5251767a5b38ea356"
- integrity sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==
+"@eslint-community/eslint-utils@^4.2.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.4.0":
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884"
+ integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==
+
+"@eslint/eslintrc@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331"
+ integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
- espree "^9.4.0"
- globals "^13.15.0"
+ espree "^9.5.2"
+ globals "^13.19.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@humanwhocodes/config-array@^0.10.5":
- version "0.10.7"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.7.tgz#6d53769fd0c222767e6452e8ebda825c22e9f0dc"
- integrity sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==
+"@eslint/js@8.43.0":
+ version "8.43.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.43.0.tgz#559ca3d9ddbd6bf907ad524320a0d14b85586af0"
+ integrity sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==
+
+"@humanwhocodes/config-array@^0.11.10":
+ version "0.11.10"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
+ integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
- minimatch "^3.0.4"
-
-"@humanwhocodes/gitignore-to-minimatch@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d"
- integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==
+ minimatch "^3.0.5"
"@humanwhocodes/module-importer@^1.0.1":
version "1.0.1"
@@ -80,7 +92,7 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
-"@nodelib/fs.walk@^1.2.3":
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
@@ -100,13 +112,13 @@
is-module "^1.0.0"
resolve "^1.19.0"
-"@rollup/plugin-typescript@^8.5.0":
- version "8.5.0"
- resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz#7ea11599a15b0a30fa7ea69ce3b791d41b862515"
- integrity sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==
+"@rollup/plugin-typescript@^11.1.1":
+ version "11.1.1"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.1.tgz#258663a7aa6b51390dd39ae6e5502f2c4b2807cb"
+ integrity sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==
dependencies:
- "@rollup/pluginutils" "^3.1.0"
- resolve "^1.17.0"
+ "@rollup/pluginutils" "^5.0.1"
+ resolve "^1.22.1"
"@rollup/pluginutils@^3.1.0":
version "3.1.0"
@@ -117,6 +129,15 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
+"@rollup/pluginutils@^5.0.1":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
+ integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
+ dependencies:
+ "@types/estree" "^1.0.0"
+ estree-walker "^2.0.2"
+ picomatch "^2.3.1"
+
"@sindresorhus/is@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
@@ -169,6 +190,11 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+"@types/estree@^1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194"
+ integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==
+
"@types/http-cache-semantics@*":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
@@ -215,6 +241,11 @@
dependencies:
"@types/node" "*"
+"@types/semver@^7.3.12":
+ version "7.3.13"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
+ integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
+
"@types/ua-parser-js@^0.7.33":
version "0.7.36"
resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz#9bd0b47f26b5a3151be21ba4ce9f5fa457c5f190"
@@ -237,84 +268,88 @@
dependencies:
"@types/node" "*"
-"@typescript-eslint/eslint-plugin@^5.36.2":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.1.tgz#9f05d42fa8fb9f62304cc2f5c2805e03c01c2620"
- integrity sha512-ky7EFzPhqz3XlhS7vPOoMDaQnQMn+9o5ICR9CPr/6bw8HrFkzhMSxuA3gRfiJVvs7geYrSeawGJjZoZQKCOglQ==
+"@typescript-eslint/eslint-plugin@^5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz#8d466aa21abea4c3f37129997b198d141f09e76f"
+ integrity sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==
dependencies:
- "@typescript-eslint/scope-manager" "5.38.1"
- "@typescript-eslint/type-utils" "5.38.1"
- "@typescript-eslint/utils" "5.38.1"
+ "@eslint-community/regexpp" "^4.4.0"
+ "@typescript-eslint/scope-manager" "5.59.11"
+ "@typescript-eslint/type-utils" "5.59.11"
+ "@typescript-eslint/utils" "5.59.11"
debug "^4.3.4"
+ grapheme-splitter "^1.0.4"
ignore "^5.2.0"
- regexpp "^3.2.0"
+ natural-compare-lite "^1.4.0"
semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/parser@^5.36.2":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.38.1.tgz#c577f429f2c32071b92dff4af4f5fbbbd2414bd0"
- integrity sha512-LDqxZBVFFQnQRz9rUZJhLmox+Ep5kdUmLatLQnCRR6523YV+XhRjfYzStQ4MheFA8kMAfUlclHSbu+RKdRwQKw==
+"@typescript-eslint/parser@^5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.11.tgz#af7d4b7110e3068ce0b97550736de455e4250103"
+ integrity sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==
dependencies:
- "@typescript-eslint/scope-manager" "5.38.1"
- "@typescript-eslint/types" "5.38.1"
- "@typescript-eslint/typescript-estree" "5.38.1"
+ "@typescript-eslint/scope-manager" "5.59.11"
+ "@typescript-eslint/types" "5.59.11"
+ "@typescript-eslint/typescript-estree" "5.59.11"
debug "^4.3.4"
-"@typescript-eslint/scope-manager@5.38.1":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.38.1.tgz#f87b289ef8819b47189351814ad183e8801d5764"
- integrity sha512-BfRDq5RidVU3RbqApKmS7RFMtkyWMM50qWnDAkKgQiezRtLKsoyRKIvz1Ok5ilRWeD9IuHvaidaLxvGx/2eqTQ==
+"@typescript-eslint/scope-manager@5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz#5d131a67a19189c42598af9fb2ea1165252001ce"
+ integrity sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==
dependencies:
- "@typescript-eslint/types" "5.38.1"
- "@typescript-eslint/visitor-keys" "5.38.1"
+ "@typescript-eslint/types" "5.59.11"
+ "@typescript-eslint/visitor-keys" "5.59.11"
-"@typescript-eslint/type-utils@5.38.1":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.38.1.tgz#7f038fcfcc4ade4ea76c7c69b2aa25e6b261f4c1"
- integrity sha512-UU3j43TM66gYtzo15ivK2ZFoDFKKP0k03MItzLdq0zV92CeGCXRfXlfQX5ILdd4/DSpHkSjIgLLLh1NtkOJOAw==
+"@typescript-eslint/type-utils@5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz#5eb67121808a84cb57d65a15f48f5bdda25f2346"
+ integrity sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==
dependencies:
- "@typescript-eslint/typescript-estree" "5.38.1"
- "@typescript-eslint/utils" "5.38.1"
+ "@typescript-eslint/typescript-estree" "5.59.11"
+ "@typescript-eslint/utils" "5.59.11"
debug "^4.3.4"
tsutils "^3.21.0"
-"@typescript-eslint/types@5.38.1":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.38.1.tgz#74f9d6dcb8dc7c58c51e9fbc6653ded39e2e225c"
- integrity sha512-QTW1iHq1Tffp9lNfbfPm4WJabbvpyaehQ0SrvVK2yfV79SytD9XDVxqiPvdrv2LK7DGSFo91TB2FgWanbJAZXg==
+"@typescript-eslint/types@5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.11.tgz#1a9018fe3c565ba6969561f2a49f330cf1fe8db1"
+ integrity sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==
-"@typescript-eslint/typescript-estree@5.38.1":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.1.tgz#657d858d5d6087f96b638ee383ee1cff52605a1e"
- integrity sha512-99b5e/Enoe8fKMLdSuwrfH/C0EIbpUWmeEKHmQlGZb8msY33qn1KlkFww0z26o5Omx7EVjzVDCWEfrfCDHfE7g==
+"@typescript-eslint/typescript-estree@5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz#b2caaa31725e17c33970c1197bcd54e3c5f42b9f"
+ integrity sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==
dependencies:
- "@typescript-eslint/types" "5.38.1"
- "@typescript-eslint/visitor-keys" "5.38.1"
+ "@typescript-eslint/types" "5.59.11"
+ "@typescript-eslint/visitor-keys" "5.59.11"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/utils@5.38.1":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.38.1.tgz#e3ac37d7b33d1362bb5adf4acdbe00372fb813ef"
- integrity sha512-oIuUiVxPBsndrN81oP8tXnFa/+EcZ03qLqPDfSZ5xIJVm7A9V0rlkQwwBOAGtrdN70ZKDlKv+l1BeT4eSFxwXA==
+"@typescript-eslint/utils@5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.11.tgz#9dbff49dc80bfdd9289f9f33548f2e8db3c59ba1"
+ integrity sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==
dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
- "@typescript-eslint/scope-manager" "5.38.1"
- "@typescript-eslint/types" "5.38.1"
- "@typescript-eslint/typescript-estree" "5.38.1"
+ "@types/semver" "^7.3.12"
+ "@typescript-eslint/scope-manager" "5.59.11"
+ "@typescript-eslint/types" "5.59.11"
+ "@typescript-eslint/typescript-estree" "5.59.11"
eslint-scope "^5.1.1"
- eslint-utils "^3.0.0"
+ semver "^7.3.7"
-"@typescript-eslint/visitor-keys@5.38.1":
- version "5.38.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.1.tgz#508071bfc6b96d194c0afe6a65ad47029059edbc"
- integrity sha512-bSHr1rRxXt54+j2n4k54p4fj8AHJ49VDWtjpImOpzQj4qjAiOpPni+V1Tyajh19Api1i844F757cur8wH3YvOA==
+"@typescript-eslint/visitor-keys@5.59.11":
+ version "5.59.11"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz#dca561ddad169dc27d62396d64f45b2d2c3ecc56"
+ integrity sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==
dependencies:
- "@typescript-eslint/types" "5.38.1"
+ "@typescript-eslint/types" "5.59.11"
eslint-visitor-keys "^3.3.0"
"@wdio/config@7.26.0":
@@ -1161,7 +1196,7 @@ caw@^2.0.1:
tunnel-agent "^0.6.0"
url-to-options "^1.0.1"
-chalk@^2.0.0, chalk@^2.3.0:
+chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1649,9 +1684,9 @@ debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, de
ms "2.1.2"
decode-uri-component@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
- integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
+ integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
decompress-response@^3.3.0:
version "3.3.0"
@@ -2003,7 +2038,7 @@ engine.io@~6.2.0:
engine.io-parser "~5.0.3"
ws "~8.2.3"
-enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0:
+enhanced-resolve@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec"
integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==
@@ -2012,6 +2047,14 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0:
memory-fs "^0.5.0"
tapable "^1.0.0"
+enhanced-resolve@^5.0.0:
+ version "5.15.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
+ integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.2.0"
+
ent@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
@@ -2070,10 +2113,10 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-eslint-config-prettier@^8.5.0:
- version "8.5.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1"
- integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==
+eslint-config-prettier@^8.8.0:
+ version "8.8.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348"
+ integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==
eslint-plugin-prettier@^4.2.1:
version "4.2.1"
@@ -2098,64 +2141,58 @@ eslint-scope@^5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
-eslint-scope@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
- integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
+eslint-scope@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
+ integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
-eslint-utils@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
- integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
- dependencies:
- eslint-visitor-keys "^2.0.0"
-
-eslint-visitor-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
- integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
-
eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-eslint@^8.23.0:
- version "8.24.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.24.0.tgz#489516c927a5da11b3979dbfb2679394523383c8"
- integrity sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==
- dependencies:
- "@eslint/eslintrc" "^1.3.2"
- "@humanwhocodes/config-array" "^0.10.5"
- "@humanwhocodes/gitignore-to-minimatch" "^1.0.2"
+eslint-visitor-keys@^3.4.1:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
+ integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
+
+eslint@^8.43.0:
+ version "8.43.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.43.0.tgz#3e8c6066a57097adfd9d390b8fc93075f257a094"
+ integrity sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.4.0"
+ "@eslint/eslintrc" "^2.0.3"
+ "@eslint/js" "8.43.0"
+ "@humanwhocodes/config-array" "^0.11.10"
"@humanwhocodes/module-importer" "^1.0.1"
+ "@nodelib/fs.walk" "^1.2.8"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.3.2"
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
- eslint-scope "^7.1.1"
- eslint-utils "^3.0.0"
- eslint-visitor-keys "^3.3.0"
- espree "^9.4.0"
- esquery "^1.4.0"
+ eslint-scope "^7.2.0"
+ eslint-visitor-keys "^3.4.1"
+ espree "^9.5.2"
+ esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
find-up "^5.0.0"
- glob-parent "^6.0.1"
- globals "^13.15.0"
- globby "^11.1.0"
- grapheme-splitter "^1.0.4"
+ glob-parent "^6.0.2"
+ globals "^13.19.0"
+ graphemer "^1.4.0"
ignore "^5.2.0"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
- js-sdsl "^4.1.4"
+ is-path-inside "^3.0.3"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
@@ -2163,24 +2200,23 @@ eslint@^8.23.0:
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.1"
- regexpp "^3.2.0"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
-espree@^9.4.0:
- version "9.4.0"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a"
- integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==
+espree@^9.5.2:
+ version "9.5.2"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b"
+ integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==
dependencies:
acorn "^8.8.0"
acorn-jsx "^5.3.2"
- eslint-visitor-keys "^3.3.0"
+ eslint-visitor-keys "^3.4.1"
-esquery@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
- integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
+esquery@^1.4.2:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
dependencies:
estraverse "^5.1.0"
@@ -2211,6 +2247,11 @@ estree-walker@^1.0.1:
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+estree-walker@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+ integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@@ -2711,7 +2752,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"
-glob-parent@^6.0.1:
+glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
@@ -2766,10 +2807,10 @@ global-agent@^2.1.12:
semver "^7.3.2"
serialize-error "^7.0.1"
-globals@^13.15.0:
- version "13.17.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
- integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==
+globals@^13.19.0:
+ version "13.19.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8"
+ integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==
dependencies:
type-fest "^0.20.2"
@@ -2876,11 +2917,21 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+graceful-fs@^4.2.4:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
grapheme-splitter@^1.0.2, grapheme-splitter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
+graphemer@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
has-bigints@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
@@ -3202,6 +3253,13 @@ is-callable@^1.1.3:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
+is-core-module@^2.11.0:
+ version "2.12.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd"
+ integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
+ dependencies:
+ has "^1.0.3"
+
is-core-module@^2.2.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
@@ -3209,13 +3267,6 @@ is-core-module@^2.2.0:
dependencies:
has "^1.0.3"
-is-core-module@^2.9.0:
- version "2.10.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
- integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
- dependencies:
- has "^1.0.3"
-
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -3342,6 +3393,11 @@ is-object@^1.0.1:
resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf"
integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -3481,11 +3537,6 @@ jest-worker@^26.2.1:
merge-stream "^2.0.0"
supports-color "^7.0.0"
-js-sdsl@^4.1.4:
- version "4.1.4"
- resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.4.tgz#78793c90f80e8430b7d8dc94515b6c77d98a26a6"
- integrity sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==
-
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -3534,9 +3585,9 @@ json-stringify-safe@^5.0.1:
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
json5@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
- integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
+ integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
dependencies:
minimist "^1.2.0"
@@ -3695,7 +3746,7 @@ loader-runner@^2.4.0:
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
-loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
+loader-utils@^1.1.0, loader-utils@^1.2.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
@@ -4017,7 +4068,7 @@ minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
+minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@@ -4031,12 +4082,7 @@ minimatch@^5.0.0, minimatch@^5.0.1:
dependencies:
brace-expansion "^2.0.1"
-minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
-minimist@^1.2.6:
+minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
@@ -4128,6 +4174,11 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+natural-compare-lite@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
+ integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -4638,10 +4689,10 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
-prettier@^2.7.1:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
- integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
+prettier@^2.8.8:
+ version "2.8.8"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
+ integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
printj@~1.1.0:
version "1.1.2"
@@ -4915,11 +4966,6 @@ regexp.prototype.flags@^1.4.3:
define-properties "^1.1.3"
functions-have-names "^1.2.2"
-regexpp@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
- integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
-
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@@ -4968,12 +5014,12 @@ resolve@^1.10.0, resolve@^1.19.0:
is-core-module "^2.2.0"
path-parse "^1.0.6"
-resolve@^1.17.0:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+resolve@^1.22.1:
+ version "1.22.2"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
+ integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
- is-core-module "^2.9.0"
+ is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
@@ -5159,26 +5205,14 @@ semver-truncate@^1.1.2:
semver "^5.3.0"
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@^6.0.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-semver@^7.3.2:
- version "7.3.5"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
- integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
- dependencies:
- lru-cache "^6.0.0"
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
-semver@^7.3.7:
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
- integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
+semver@^7.3.2, semver@^7.3.4, semver@^7.3.7:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
@@ -5334,9 +5368,9 @@ socket.io-adapter@~2.4.0:
integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==
socket.io-parser@~4.2.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5"
- integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.3.tgz#926bcc6658e2ae0883dc9dee69acbdc76e4e3667"
+ integrity sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
@@ -5617,6 +5651,11 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
+tapable@^2.2.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
tar-fs@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
@@ -5793,16 +5832,15 @@ trim-repeated@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
-ts-loader@^6.0.4:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.2.tgz#dffa3879b01a1a1e0a4b85e2b8421dc0dfff1c58"
- integrity sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ==
+ts-loader@^9.4.3:
+ version "9.4.3"
+ resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.3.tgz#55cfa7c28dd82a2de968ae45c3adb75fb888b27e"
+ integrity sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA==
dependencies:
- chalk "^2.3.0"
- enhanced-resolve "^4.0.0"
- loader-utils "^1.0.2"
+ chalk "^4.1.0"
+ enhanced-resolve "^5.0.0"
micromatch "^4.0.0"
- semver "^6.0.0"
+ semver "^7.3.4"
tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
@@ -5814,10 +5852,10 @@ tslib@^2.0.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
-tslib@^2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
- integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
+tslib@^2.5.3:
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913"
+ integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==
tsutils@^3.21.0:
version "3.21.0"
@@ -5878,15 +5916,15 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@^4.8.2:
- version "4.8.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790"
- integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==
+typescript@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826"
+ integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==
ua-parser-js@^0.7.30:
- version "0.7.32"
- resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.32.tgz#cd8c639cdca949e30fa68c44b7813ef13e36d211"
- integrity sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==
+ version "0.7.33"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532"
+ integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==
ua-parser-js@^1.0.1:
version "1.0.32"
@@ -6244,9 +6282,9 @@ which@^2.0.1, which@^2.0.2:
isexe "^2.0.0"
word-wrap@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
- integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
+ integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
worker-farm@^1.7.0:
version "1.7.0"